From 98c381468b97317b6280e40aa16216cf568e41f2 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 2 Apr 2017 16:57:50 +0200 Subject: [PATCH 01/59] Add support of unicode to all file operations --- src/host/os_chdir.c | 3 ++- src/host/os_copyfile.c | 3 ++- src/host/os_getcwd.c | 8 +++++++- src/host/os_isdir.c | 8 +++++++- src/host/os_isfile.c | 10 ++++++--- src/host/os_islink.c | 4 +++- src/host/os_locate.c | 2 +- src/host/os_match.c | 15 ++++++++------ src/host/os_pathsearch.c | 2 +- src/host/os_rmdir.c | 3 ++- src/host/os_writefile_ifnotequal.c | 2 +- src/host/premake.c | 8 ++++++-- src/host/premake.h | 7 ++++++- src/host/utf8handling.c | 33 ++++++++++++++++++++++++++++++ 14 files changed, 87 insertions(+), 21 deletions(-) create mode 100644 src/host/utf8handling.c diff --git a/src/host/os_chdir.c b/src/host/os_chdir.c index 5d09c165..3b930127 100644 --- a/src/host/os_chdir.c +++ b/src/host/os_chdir.c @@ -14,7 +14,8 @@ int do_chdir(lua_State* L, const char* path) (void)(L); /* warning: unused parameter */ #if PLATFORM_WINDOWS - z = SetCurrentDirectoryA(path); + z = SetCurrentDirectoryW(utf8_towide(L, path)); + lua_pop(L, 1); #else z = !chdir(path); #endif diff --git a/src/host/os_copyfile.c b/src/host/os_copyfile.c index 526afb5c..434694a7 100644 --- a/src/host/os_copyfile.c +++ b/src/host/os_copyfile.c @@ -14,7 +14,8 @@ int os_copyfile(lua_State* L) const char* dst = luaL_checkstring(L, 2); #if PLATFORM_WINDOWS - z = CopyFileA(src, dst, FALSE); + z = CopyFileW(utf8_towide(L, src), utf8_towide(L, dst), FALSE); + lua_pop(L, 2); #else lua_pushfstring(L, "cp \"%s\" \"%s\"", src, dst); z = (system(lua_tostring(L, -1)) == 0); diff --git a/src/host/os_getcwd.c b/src/host/os_getcwd.c index 3262865b..4c4d7453 100644 --- a/src/host/os_getcwd.c +++ b/src/host/os_getcwd.c @@ -5,6 +5,7 @@ */ #include "premake.h" +#include "assert.h" int os_getcwd(lua_State* L) { @@ -24,8 +25,13 @@ int do_getcwd(char* buffer, size_t size) int result; #if PLATFORM_WINDOWS - result = (GetCurrentDirectoryA(size, buffer) != 0); + assert(size == 0x4000); + wchar_t wbuffer[0x4000]; + + result = (GetCurrentDirectoryW(size, wbuffer) != 0); if (result) { + WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, buffer, size, NULL, NULL); + do_translate(buffer, '/'); } #else diff --git a/src/host/os_isdir.c b/src/host/os_isdir.c index d7e73c9c..171cdf6d 100644 --- a/src/host/os_isdir.c +++ b/src/host/os_isdir.c @@ -18,6 +18,8 @@ int os_isdir(lua_State* L) const char* path = luaL_checkstring(L, 1); #ifdef _WIN32 int attr; + + const wchar_t* wide_path = utf8_towide(L, path); #endif /* empty path is equivalent to ".", must be true */ @@ -27,7 +29,7 @@ int os_isdir(lua_State* L) } #ifdef _WIN32 // Use Windows-specific GetFileAttributes since it deals with symbolic links. - else if ((attr = GetFileAttributesA(path)) != INVALID_FILE_ATTRIBUTES) + else if ((attr = GetFileAttributesW(wide_path)) != INVALID_FILE_ATTRIBUTES) { int isdir = (attr & FILE_ATTRIBUTE_DIRECTORY) != 0; lua_pushboolean(L, isdir); @@ -42,6 +44,10 @@ int os_isdir(lua_State* L) { lua_pushboolean(L, 0); } + +#ifdef _WIN32 + lua_pop(L, -2); /* pop wide string */ +#endif return 1; } diff --git a/src/host/os_isfile.c b/src/host/os_isfile.c index 34c5c527..2c737e1e 100644 --- a/src/host/os_isfile.c +++ b/src/host/os_isfile.c @@ -11,15 +11,19 @@ int os_isfile(lua_State* L) { const char* filename = luaL_checkstring(L, 1); - lua_pushboolean(L, do_isfile(filename)); + lua_pushboolean(L, do_isfile(L, filename)); return 1; } -int do_isfile(const char* filename) +int do_isfile(lua_State* L, const char* filename) { + (void)(L); /* warning: unused parameter */ + #if PLATFORM_WINDOWS - DWORD attrib = GetFileAttributesA(filename); + DWORD attrib = GetFileAttributesW(utf8_towide(L, filename)); + lua_pop(L, 1); + if (attrib != INVALID_FILE_ATTRIBUTES) { return (attrib & FILE_ATTRIBUTE_DIRECTORY) == 0; diff --git a/src/host/os_islink.c b/src/host/os_islink.c index ff495c34..61b845fc 100644 --- a/src/host/os_islink.c +++ b/src/host/os_islink.c @@ -14,7 +14,9 @@ int os_islink(lua_State* L) #if PLATFORM_WINDOWS { - DWORD attr = GetFileAttributesA(path); + DWORD attr = GetFileAttributesW(utf8_towide(L, path)); + lua_pop(L, 1); + if (attr != INVALID_FILE_ATTRIBUTES) { lua_pushboolean(L, (attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0); return 1; diff --git a/src/host/os_locate.c b/src/host/os_locate.c index 6313f7a9..b72b1576 100644 --- a/src/host/os_locate.c +++ b/src/host/os_locate.c @@ -37,7 +37,7 @@ int os_locate(lua_State* L) const char* name = lua_tostring(L, i); /* Direct path to file? Return as absolute path */ - if (do_isfile(name)) { + if (do_isfile(L, name)) { lua_pushcfunction(L, path_getabsolute); lua_pushvalue(L, i); lua_call(L, 1, 1); diff --git a/src/host/os_match.c b/src/host/os_match.c index dd1e7f27..109d1c1a 100644 --- a/src/host/os_match.c +++ b/src/host/os_match.c @@ -15,14 +15,17 @@ typedef struct struct_MatchInfo { HANDLE handle; int is_first; - WIN32_FIND_DATAA entry; + WIN32_FIND_DATAW entry; } MatchInfo; int os_matchstart(lua_State* L) { const char* mask = luaL_checkstring(L, 1); MatchInfo* m = (MatchInfo*)malloc(sizeof(MatchInfo)); - m->handle = FindFirstFileA(mask, &m->entry); + + m->handle = FindFirstFileW(utf8_towide(L, mask), &m->entry); + lua_pop(L, 1); + m->is_first = 1; lua_pushlightuserdata(L, m); return 1; @@ -40,7 +43,7 @@ int os_matchdone(lua_State* L) int os_matchname(lua_State* L) { MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1); - lua_pushstring(L, m->entry.cFileName); + utf8_fromwide(L, m->entry.cFileName); return 1; } @@ -64,11 +67,11 @@ int os_matchnext(lua_State* L) m->is_first = 0; else { - if (!FindNextFileA(m->handle, &m->entry)) + if (!FindNextFileW(m->handle, &m->entry)) return 0; } - if (strcmp(m->entry.cFileName, ".") != 0 && strcmp(m->entry.cFileName, "..") != 0) + if (wcscmp(m->entry.cFileName, L".") != 0 && wcscmp(m->entry.cFileName, L"..") != 0) { lua_pushboolean(L, 1); return 1; @@ -159,7 +162,7 @@ int os_matchisfile(lua_State* L) fname = lua_tostring(L, -1); lua_pop(L, 1); - lua_pushboolean(L, do_isfile(fname)); + lua_pushboolean(L, do_isfile(L, fname)); } return 1; } diff --git a/src/host/os_pathsearch.c b/src/host/os_pathsearch.c index ec152258..85e49a02 100644 --- a/src/host/os_pathsearch.c +++ b/src/host/os_pathsearch.c @@ -58,7 +58,7 @@ int do_pathsearch(lua_State* L, const char* filename, const char* path) lua_concat(L, 3); /* test it - if it exists, return the absolute path */ - if (do_isfile(lua_tostring(L, -1))) + if (do_isfile(L, lua_tostring(L, -1))) { lua_pop(L, 1); lua_pushcfunction(L, path_getabsolute); diff --git a/src/host/os_rmdir.c b/src/host/os_rmdir.c index 7de669a9..01e6d1cc 100644 --- a/src/host/os_rmdir.c +++ b/src/host/os_rmdir.c @@ -14,7 +14,8 @@ int os_rmdir(lua_State* L) const char* path = luaL_checkstring(L, 1); #if PLATFORM_WINDOWS - z = RemoveDirectoryA(path); + z = RemoveDirectoryW(utf8_towide(L, path)); + lua_pop(L, 1); #else z = (0 == rmdir(path)); #endif diff --git a/src/host/os_writefile_ifnotequal.c b/src/host/os_writefile_ifnotequal.c index 9d4dcbb7..88265d29 100644 --- a/src/host/os_writefile_ifnotequal.c +++ b/src/host/os_writefile_ifnotequal.c @@ -75,7 +75,7 @@ int os_writefile_ifnotequal(lua_State* L) const char* dst = luaL_checkstring(L, 2); // if destination exist, and they are the same, no need to copy. - if (do_isfile(dst) && compare_file(content, length, dst)) + if (do_isfile(L, dst) && compare_file(content, length, dst)) { lua_pushinteger(L, 0); return 1; diff --git a/src/host/premake.c b/src/host/premake.c index 8c26b306..aa8774ec 100644 --- a/src/host/premake.c +++ b/src/host/premake.c @@ -229,9 +229,13 @@ int premake_locate_executable(lua_State* L, const char* argv0) const char* path = NULL; #if PLATFORM_WINDOWS - DWORD len = GetModuleFileNameA(NULL, buffer, PATH_MAX); + wchar_t widebuffer[PATH_MAX]; + + DWORD len = GetModuleFileNameW(NULL, widebuffer, PATH_MAX); if (len > 0) { + WideCharToMultiByte(CP_UTF8, 0, widebuffer, len, buffer, PATH_MAX, NULL, NULL); + buffer[len] = 0; path = buffer; } @@ -320,7 +324,7 @@ int premake_locate_executable(lua_State* L, const char* argv0) int premake_test_file(lua_State* L, const char* filename, int searchMask) { if (searchMask & TEST_LOCAL) { - if (do_isfile(filename)) { + if (do_isfile(L, filename)) { lua_pushcfunction(L, path_getabsolute); lua_pushstring(L, filename); lua_call(L, 1, 1); diff --git a/src/host/premake.h b/src/host/premake.h index d9bb7b33..b4b20a3a 100644 --- a/src/host/premake.h +++ b/src/host/premake.h @@ -80,12 +80,17 @@ unsigned long do_hash(const char* str, int seed); void do_getabsolute(char* result, const char* value, const char* relative_to); int do_getcwd(char* buffer, size_t size); int do_isabsolute(const char* path); -int do_isfile(const char* filename); +int do_isfile(lua_State* L, const char* filename); int do_locate(lua_State* L, const char* filename, const char* path); void do_normalize(lua_State* L, char* buffer, const char* path); int do_pathsearch(lua_State* L, const char* filename, const char* path); void do_translate(char* value, const char sep); +/* Unicode conversion helper functions (required for Windows systems) */ +#ifdef PLATFORM_WINDOWS +const char* utf8_fromwide(lua_State* L, const wchar_t* wstr); +const wchar_t* utf8_towide(lua_State* L, const char* str); +#endif /* Built-in functions */ int criteria_compile(lua_State* L); diff --git a/src/host/utf8handling.c b/src/host/utf8handling.c new file mode 100644 index 00000000..e9bb9374 --- /dev/null +++ b/src/host/utf8handling.c @@ -0,0 +1,33 @@ +/** + * \file utf8handking.c + * \brief Handles conversions between Unicode (UTF-8) and system native encoding (wide chars on Windows) + * \author Copyright (c) 2017 Jérôme Leclercq and the Premake project + */ + +#include "premake.h" +#include "stdlib.h" + +#ifdef PLATFORM_WINDOWS +const char* utf8_fromwide(lua_State* L, const wchar_t* wstr) +{ + int size_required = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); + + char* unicode_str = (char*) malloc(size_required * sizeof(char)); + WideCharToMultiByte(CP_UTF8, 0, wstr, -1, unicode_str, size_required, NULL, NULL); + + lua_pushstring(L, unicode_str); + free(unicode_str); + + return unicode_str; +} + +const wchar_t* utf8_towide(lua_State* L, const char* str) +{ + int size_required = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); + + wchar_t* wide_string = (wchar_t*) lua_newuserdata(L, size_required * sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, str, -1, wide_string, size_required); + + return wide_string; +} +#endif From 0cc98c5f668a1b640f176cfb69b69880e9d90150 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 2 Apr 2017 17:06:09 +0200 Subject: [PATCH 02/59] Fix problematic assert --- src/host/os_getcwd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/host/os_getcwd.c b/src/host/os_getcwd.c index 58c49e10..5cd9bab1 100644 --- a/src/host/os_getcwd.c +++ b/src/host/os_getcwd.c @@ -5,7 +5,6 @@ */ #include "premake.h" -#include "assert.h" int os_getcwd(lua_State* L) { @@ -25,10 +24,9 @@ int do_getcwd(char* buffer, size_t size) int result; #if PLATFORM_WINDOWS - assert(size == 0x4000); - wchar_t wbuffer[0x4000]; + wchar_t wbuffer[MAX_PATH]; - result = (GetCurrentDirectoryW((DWORD)size, wbuffer) != 0); + result = (GetCurrentDirectoryW(MAX_PATH, wbuffer) != 0); if (result) { WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, buffer, size, NULL, NULL); From d83689d7ee12808b0d1a1eef8977162fee0d250f Mon Sep 17 00:00:00 2001 From: Lynix Date: Mon, 3 Apr 2017 09:15:59 +0200 Subject: [PATCH 03/59] Fix Lua stack corruption with os.isdir --- src/host/os_isdir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/host/os_isdir.c b/src/host/os_isdir.c index 171cdf6d..91cdd6fb 100644 --- a/src/host/os_isdir.c +++ b/src/host/os_isdir.c @@ -46,7 +46,7 @@ int os_isdir(lua_State* L) } #ifdef _WIN32 - lua_pop(L, -2); /* pop wide string */ + lua_remove(L, -2); /* pop wide string */ #endif return 1; From 9c4c998a2b3424c9047acec5186f23d2e4c10db6 Mon Sep 17 00:00:00 2001 From: Lynix Date: Tue, 4 Apr 2017 09:03:29 +0200 Subject: [PATCH 04/59] Rework unicode encoding/decoding (Windows) --- src/host/os_chdir.c | 10 ++++++++-- src/host/os_copyfile.c | 18 ++++++++++++++++-- src/host/os_getcwd.c | 6 +++--- src/host/os_isdir.c | 13 +++++++------ src/host/os_isfile.c | 10 ++++++++-- src/host/os_islink.c | 9 +++++++-- src/host/os_match.c | 22 ++++++++++++++++++---- src/host/os_rmdir.c | 10 ++++++++-- src/host/premake.h | 6 ------ src/host/utf8handling.c | 33 --------------------------------- 10 files changed, 75 insertions(+), 62 deletions(-) delete mode 100644 src/host/utf8handling.c diff --git a/src/host/os_chdir.c b/src/host/os_chdir.c index 3b930127..28aa0fcd 100644 --- a/src/host/os_chdir.c +++ b/src/host/os_chdir.c @@ -14,8 +14,14 @@ int do_chdir(lua_State* L, const char* path) (void)(L); /* warning: unused parameter */ #if PLATFORM_WINDOWS - z = SetCurrentDirectoryW(utf8_towide(L, path)); - lua_pop(L, 1); + wchar_t wide_buffer[PATH_MAX]; + if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wide_buffer, PATH_MAX) == 0) + { + lua_pushstring(L, "unable to encode path"); + return lua_error(L); + } + + z = SetCurrentDirectoryW(wide_buffer); #else z = !chdir(path); #endif diff --git a/src/host/os_copyfile.c b/src/host/os_copyfile.c index 434694a7..e15c93dd 100644 --- a/src/host/os_copyfile.c +++ b/src/host/os_copyfile.c @@ -14,8 +14,22 @@ int os_copyfile(lua_State* L) const char* dst = luaL_checkstring(L, 2); #if PLATFORM_WINDOWS - z = CopyFileW(utf8_towide(L, src), utf8_towide(L, dst), FALSE); - lua_pop(L, 2); + wchar_t wide_src[PATH_MAX]; + wchar_t wide_dst[PATH_MAX]; + + if (MultiByteToWideChar(CP_UTF8, 0, src, -1, wide_src, PATH_MAX) == 0) + { + lua_pushstring(L, "unable to encode source path"); + return lua_error(L); + } + + if (MultiByteToWideChar(CP_UTF8, 0, dst, -1, wide_dst, PATH_MAX) == 0) + { + lua_pushstring(L, "unable to encode source path"); + return lua_error(L); + } + + z = CopyFileW(wide_src, wide_dst, FALSE); #else lua_pushfstring(L, "cp \"%s\" \"%s\"", src, dst); z = (system(lua_tostring(L, -1)) == 0); diff --git a/src/host/os_getcwd.c b/src/host/os_getcwd.c index 5cd9bab1..5a3e2931 100644 --- a/src/host/os_getcwd.c +++ b/src/host/os_getcwd.c @@ -24,9 +24,9 @@ int do_getcwd(char* buffer, size_t size) int result; #if PLATFORM_WINDOWS - wchar_t wbuffer[MAX_PATH]; - - result = (GetCurrentDirectoryW(MAX_PATH, wbuffer) != 0); + wchar_t wbuffer[PATH_MAX]; + + result = (GetCurrentDirectoryW(PATH_MAX, wbuffer) != 0); if (result) { WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, buffer, size, NULL, NULL); diff --git a/src/host/os_isdir.c b/src/host/os_isdir.c index 91cdd6fb..b3e2ccdd 100644 --- a/src/host/os_isdir.c +++ b/src/host/os_isdir.c @@ -18,8 +18,13 @@ int os_isdir(lua_State* L) const char* path = luaL_checkstring(L, 1); #ifdef _WIN32 int attr; - - const wchar_t* wide_path = utf8_towide(L, path); + + wchar_t wide_path[PATH_MAX]; + if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wide_path, PATH_MAX) == 0) + { + lua_pushstring(L, "unable to encode path"); + return lua_error(L); + } #endif /* empty path is equivalent to ".", must be true */ @@ -44,10 +49,6 @@ int os_isdir(lua_State* L) { lua_pushboolean(L, 0); } - -#ifdef _WIN32 - lua_remove(L, -2); /* pop wide string */ -#endif return 1; } diff --git a/src/host/os_isfile.c b/src/host/os_isfile.c index 2c737e1e..2bad6f04 100644 --- a/src/host/os_isfile.c +++ b/src/host/os_isfile.c @@ -21,9 +21,15 @@ int do_isfile(lua_State* L, const char* filename) (void)(L); /* warning: unused parameter */ #if PLATFORM_WINDOWS - DWORD attrib = GetFileAttributesW(utf8_towide(L, filename)); - lua_pop(L, 1); + wchar_t wide_path[PATH_MAX]; + if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, wide_path, PATH_MAX) == 0) + { + lua_pushstring(L, "unable to encode filepath"); + return lua_error(L); + } + + DWORD attrib = GetFileAttributesW(wide_path); if (attrib != INVALID_FILE_ATTRIBUTES) { return (attrib & FILE_ATTRIBUTE_DIRECTORY) == 0; diff --git a/src/host/os_islink.c b/src/host/os_islink.c index 61b845fc..1c2dee91 100644 --- a/src/host/os_islink.c +++ b/src/host/os_islink.c @@ -14,9 +14,14 @@ int os_islink(lua_State* L) #if PLATFORM_WINDOWS { - DWORD attr = GetFileAttributesW(utf8_towide(L, path)); - lua_pop(L, 1); + wchar_t wide_path[PATH_MAX]; + if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wide_path, PATH_MAX) == 0) + { + lua_pushstring(L, "unable to encode path"); + return lua_error(L); + } + DWORD attr = GetFileAttributesW(wide_path); if (attr != INVALID_FILE_ATTRIBUTES) { lua_pushboolean(L, (attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0); return 1; diff --git a/src/host/os_match.c b/src/host/os_match.c index 109d1c1a..2a25df68 100644 --- a/src/host/os_match.c +++ b/src/host/os_match.c @@ -21,11 +21,17 @@ typedef struct struct_MatchInfo int os_matchstart(lua_State* L) { const char* mask = luaL_checkstring(L, 1); + + wchar_t wide_mask[PATH_MAX]; + if (MultiByteToWideChar(CP_UTF8, 0, mask, -1, wide_mask, PATH_MAX) == 0) + { + lua_pushstring(L, "unable to encode mask"); + return lua_error(L); + } + MatchInfo* m = (MatchInfo*)malloc(sizeof(MatchInfo)); - m->handle = FindFirstFileW(utf8_towide(L, mask), &m->entry); - lua_pop(L, 1); - + m->handle = FindFirstFileW(wide_mask, &m->entry); m->is_first = 1; lua_pushlightuserdata(L, m); return 1; @@ -43,7 +49,15 @@ int os_matchdone(lua_State* L) int os_matchname(lua_State* L) { MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1); - utf8_fromwide(L, m->entry.cFileName); + + char filename[PATH_MAX]; + if (WideCharToMultiByte(CP_UTF8, 0, m->entry.cFileName, -1, filename, PATH_MAX, NULL, NULL) == 0) + { + lua_pushstring(L, "unable to decode filename"); + return lua_error(L); + } + + lua_pushstring(L, filename); return 1; } diff --git a/src/host/os_rmdir.c b/src/host/os_rmdir.c index 01e6d1cc..46e65d9d 100644 --- a/src/host/os_rmdir.c +++ b/src/host/os_rmdir.c @@ -14,8 +14,14 @@ int os_rmdir(lua_State* L) const char* path = luaL_checkstring(L, 1); #if PLATFORM_WINDOWS - z = RemoveDirectoryW(utf8_towide(L, path)); - lua_pop(L, 1); + wchar_t wide_path[PATH_MAX]; + if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wide_path, PATH_MAX) == 0) + { + lua_pushstring(L, "unable to encode path"); + return lua_error(L); + } + + z = RemoveDirectoryW(wide_path); #else z = (0 == rmdir(path)); #endif diff --git a/src/host/premake.h b/src/host/premake.h index 4c3b9826..c8bb3f23 100644 --- a/src/host/premake.h +++ b/src/host/premake.h @@ -87,12 +87,6 @@ void do_normalize(lua_State* L, char* buffer, const char* path); int do_pathsearch(lua_State* L, const char* filename, const char* path); void do_translate(char* value, const char sep); -/* Unicode conversion helper functions (required for Windows systems) */ -#ifdef PLATFORM_WINDOWS -const char* utf8_fromwide(lua_State* L, const wchar_t* wstr); -const wchar_t* utf8_towide(lua_State* L, const char* str); -#endif - /* Built-in functions */ int criteria_compile(lua_State* L); int criteria_delete(lua_State* L); diff --git a/src/host/utf8handling.c b/src/host/utf8handling.c deleted file mode 100644 index e9bb9374..00000000 --- a/src/host/utf8handling.c +++ /dev/null @@ -1,33 +0,0 @@ -/** - * \file utf8handking.c - * \brief Handles conversions between Unicode (UTF-8) and system native encoding (wide chars on Windows) - * \author Copyright (c) 2017 Jérôme Leclercq and the Premake project - */ - -#include "premake.h" -#include "stdlib.h" - -#ifdef PLATFORM_WINDOWS -const char* utf8_fromwide(lua_State* L, const wchar_t* wstr) -{ - int size_required = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL); - - char* unicode_str = (char*) malloc(size_required * sizeof(char)); - WideCharToMultiByte(CP_UTF8, 0, wstr, -1, unicode_str, size_required, NULL, NULL); - - lua_pushstring(L, unicode_str); - free(unicode_str); - - return unicode_str; -} - -const wchar_t* utf8_towide(lua_State* L, const char* str) -{ - int size_required = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0); - - wchar_t* wide_string = (wchar_t*) lua_newuserdata(L, size_required * sizeof(wchar_t)); - MultiByteToWideChar(CP_UTF8, 0, str, -1, wide_string, size_required); - - return wide_string; -} -#endif From 479d51af81f36561d48f50921dd8ccaa06ee3227 Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Tue, 4 Apr 2017 19:02:59 +0300 Subject: [PATCH 05/59] Add JSON API (#729) * Add JSON API --- src/_manifest.lua | 2 + src/base/json.lua | 1548 ++++++++++++++++++++++++++++++++++++++ src/base/jsonwrapper.lua | 46 ++ tests/_tests.lua | 1 + tests/base/test_json.lua | 32 + 5 files changed, 1629 insertions(+) create mode 100644 src/base/json.lua create mode 100644 src/base/jsonwrapper.lua create mode 100644 tests/base/test_json.lua diff --git a/src/_manifest.lua b/src/_manifest.lua index c3cb9322..6d5dc549 100644 --- a/src/_manifest.lua +++ b/src/_manifest.lua @@ -22,6 +22,8 @@ "base/moduledownloader.lua", "base/semver.lua", "base/http.lua", + "base/json.lua", + "base/jsonwrapper.lua", -- configuration data "base/field.lua", diff --git a/src/base/json.lua b/src/base/json.lua new file mode 100644 index 00000000..2a54f4cf --- /dev/null +++ b/src/base/json.lua @@ -0,0 +1,1548 @@ +-- -*- coding: utf-8 -*- +-- +-- Simple JSON encoding and decoding in pure Lua. +-- +-- Copyright 2010-2016 Jeffrey Friedl +-- http://regex.info/blog/ +-- Latest version: http://regex.info/blog/lua/json +-- +-- This code is released under a Creative Commons CC-BY "Attribution" License: +-- http://creativecommons.org/licenses/by/3.0/deed.en_US +-- +-- It can be used for any purpose so long as: +-- 1) the copyright notice above is maintained +-- 2) the web-page links above are maintained +-- 3) the 'AUTHOR_NOTE' string below is maintained +-- +local VERSION = '20161109.21' -- version history at end of file +local AUTHOR_NOTE = "-[ JSON.lua package by Jeffrey Friedl (http://regex.info/blog/lua/json) version 20161109.21 ]-" + +-- +-- The 'AUTHOR_NOTE' variable exists so that information about the source +-- of the package is maintained even in compiled versions. It's also +-- included in OBJDEF below mostly to quiet warnings about unused variables. +-- +local OBJDEF = { + VERSION = VERSION, + AUTHOR_NOTE = AUTHOR_NOTE, +} + + +-- +-- Simple JSON encoding and decoding in pure Lua. +-- JSON definition: http://www.json.org/ +-- +-- +-- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines +-- +-- local lua_value = JSON:decode(raw_json_text) +-- +-- local raw_json_text = JSON:encode(lua_table_or_value) +-- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability +-- +-- +-- +-- DECODING (from a JSON string to a Lua table) +-- +-- +-- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines +-- +-- local lua_value = JSON:decode(raw_json_text) +-- +-- If the JSON text is for an object or an array, e.g. +-- { "what": "books", "count": 3 } +-- or +-- [ "Larry", "Curly", "Moe" ] +-- +-- the result is a Lua table, e.g. +-- { what = "books", count = 3 } +-- or +-- { "Larry", "Curly", "Moe" } +-- +-- +-- The encode and decode routines accept an optional second argument, +-- "etc", which is not used during encoding or decoding, but upon error +-- is passed along to error handlers. It can be of any type (including nil). +-- +-- +-- +-- ERROR HANDLING +-- +-- With most errors during decoding, this code calls +-- +-- JSON:onDecodeError(message, text, location, etc) +-- +-- with a message about the error, and if known, the JSON text being +-- parsed and the byte count where the problem was discovered. You can +-- replace the default JSON:onDecodeError() with your own function. +-- +-- The default onDecodeError() merely augments the message with data +-- about the text and the location if known (and if a second 'etc' +-- argument had been provided to decode(), its value is tacked onto the +-- message as well), and then calls JSON.assert(), which itself defaults +-- to Lua's built-in assert(), and can also be overridden. +-- +-- For example, in an Adobe Lightroom plugin, you might use something like +-- +-- function JSON:onDecodeError(message, text, location, etc) +-- LrErrors.throwUserError("Internal Error: invalid JSON data") +-- end +-- +-- or even just +-- +-- function JSON.assert(message) +-- LrErrors.throwUserError("Internal Error: " .. message) +-- end +-- +-- If JSON:decode() is passed a nil, this is called instead: +-- +-- JSON:onDecodeOfNilError(message, nil, nil, etc) +-- +-- and if JSON:decode() is passed HTML instead of JSON, this is called: +-- +-- JSON:onDecodeOfHTMLError(message, text, nil, etc) +-- +-- The use of the fourth 'etc' argument allows stronger coordination +-- between decoding and error reporting, especially when you provide your +-- own error-handling routines. Continuing with the the Adobe Lightroom +-- plugin example: +-- +-- function JSON:onDecodeError(message, text, location, etc) +-- local note = "Internal Error: invalid JSON data" +-- if type(etc) = 'table' and etc.photo then +-- note = note .. " while processing for " .. etc.photo:getFormattedMetadata('fileName') +-- end +-- LrErrors.throwUserError(note) +-- end +-- +-- : +-- : +-- +-- for i, photo in ipairs(photosToProcess) do +-- : +-- : +-- local data = JSON:decode(someJsonText, { photo = photo }) +-- : +-- : +-- end +-- +-- +-- +-- If the JSON text passed to decode() has trailing garbage (e.g. as with the JSON "[123]xyzzy"), +-- the method +-- +-- JSON:onTrailingGarbage(json_text, location, parsed_value, etc) +-- +-- is invoked, where: +-- +-- json_text is the original JSON text being parsed, +-- location is the count of bytes into json_text where the garbage starts (6 in the example), +-- parsed_value is the Lua result of what was successfully parsed ({123} in the example), +-- etc is as above. +-- +-- If JSON:onTrailingGarbage() does not abort, it should return the value decode() should return, +-- or nil + an error message. +-- +-- local new_value, error_message = JSON:onTrailingGarbage() +-- +-- The default handler just invokes JSON:onDecodeError("trailing garbage"...), but you can have +-- this package ignore trailing garbage via +-- +-- function JSON:onTrailingGarbage(json_text, location, parsed_value, etc) +-- return parsed_value +-- end +-- +-- +-- DECODING AND STRICT TYPES +-- +-- Because both JSON objects and JSON arrays are converted to Lua tables, +-- it's not normally possible to tell which original JSON type a +-- particular Lua table was derived from, or guarantee decode-encode +-- round-trip equivalency. +-- +-- However, if you enable strictTypes, e.g. +-- +-- JSON = assert(loadfile "JSON.lua")() --load the routines +-- JSON.strictTypes = true +-- +-- then the Lua table resulting from the decoding of a JSON object or +-- JSON array is marked via Lua metatable, so that when re-encoded with +-- JSON:encode() it ends up as the appropriate JSON type. +-- +-- (This is not the default because other routines may not work well with +-- tables that have a metatable set, for example, Lightroom API calls.) +-- +-- +-- ENCODING (from a lua table to a JSON string) +-- +-- JSON = assert(loadfile "JSON.lua")() -- one-time load of the routines +-- +-- local raw_json_text = JSON:encode(lua_table_or_value) +-- local pretty_json_text = JSON:encode_pretty(lua_table_or_value) -- "pretty printed" version for human readability +-- local custom_pretty = JSON:encode(lua_table_or_value, etc, { pretty = true, indent = "| ", align_keys = false }) +-- +-- On error during encoding, this code calls: +-- +-- JSON:onEncodeError(message, etc) +-- +-- which you can override in your local JSON object. +-- +-- The 'etc' in the error call is the second argument to encode() +-- and encode_pretty(), or nil if it wasn't provided. +-- +-- +-- ENCODING OPTIONS +-- +-- An optional third argument, a table of options, can be provided to encode(). +-- +-- encode_options = { +-- -- options for making "pretty" human-readable JSON (see "PRETTY-PRINTING" below) +-- pretty = true, +-- indent = " ", +-- align_keys = false, +-- +-- -- other output-related options +-- null = "\0", -- see "ENCODING JSON NULL VALUES" below +-- stringsAreUtf8 = false, -- see "HANDLING UNICODE LINE AND PARAGRAPH SEPARATORS FOR JAVA" below +-- } +-- +-- json_string = JSON:encode(mytable, etc, encode_options) +-- +-- +-- +-- For reference, the defaults are: +-- +-- pretty = false +-- null = nil, +-- stringsAreUtf8 = false, +-- +-- +-- +-- PRETTY-PRINTING +-- +-- Enabling the 'pretty' encode option helps generate human-readable JSON. +-- +-- pretty = JSON:encode(val, etc, { +-- pretty = true, +-- indent = " ", +-- align_keys = false, +-- }) +-- +-- encode_pretty() is also provided: it's identical to encode() except +-- that encode_pretty() provides a default options table if none given in the call: +-- +-- { pretty = true, align_keys = false, indent = " " } +-- +-- For example, if +-- +-- JSON:encode(data) +-- +-- produces: +-- +-- {"city":"Kyoto","climate":{"avg_temp":16,"humidity":"high","snowfall":"minimal"},"country":"Japan","wards":11} +-- +-- then +-- +-- JSON:encode_pretty(data) +-- +-- produces: +-- +-- { +-- "city": "Kyoto", +-- "climate": { +-- "avg_temp": 16, +-- "humidity": "high", +-- "snowfall": "minimal" +-- }, +-- "country": "Japan", +-- "wards": 11 +-- } +-- +-- The following three lines return identical results: +-- JSON:encode_pretty(data) +-- JSON:encode_pretty(data, nil, { pretty = true, align_keys = false, indent = " " }) +-- JSON:encode (data, nil, { pretty = true, align_keys = false, indent = " " }) +-- +-- An example of setting your own indent string: +-- +-- JSON:encode_pretty(data, nil, { pretty = true, indent = "| " }) +-- +-- produces: +-- +-- { +-- | "city": "Kyoto", +-- | "climate": { +-- | | "avg_temp": 16, +-- | | "humidity": "high", +-- | | "snowfall": "minimal" +-- | }, +-- | "country": "Japan", +-- | "wards": 11 +-- } +-- +-- An example of setting align_keys to true: +-- +-- JSON:encode_pretty(data, nil, { pretty = true, indent = " ", align_keys = true }) +-- +-- produces: +-- +-- { +-- "city": "Kyoto", +-- "climate": { +-- "avg_temp": 16, +-- "humidity": "high", +-- "snowfall": "minimal" +-- }, +-- "country": "Japan", +-- "wards": 11 +-- } +-- +-- which I must admit is kinda ugly, sorry. This was the default for +-- encode_pretty() prior to version 20141223.14. +-- +-- +-- HANDLING UNICODE LINE AND PARAGRAPH SEPARATORS FOR JAVA +-- +-- If the 'stringsAreUtf8' encode option is set to true, consider Lua strings not as a sequence of bytes, +-- but as a sequence of UTF-8 characters. +-- +-- Currently, the only practical effect of setting this option is that Unicode LINE and PARAGRAPH +-- separators, if found in a string, are encoded with a JSON escape instead of being dumped as is. +-- The JSON is valid either way, but encoding this way, apparently, allows the resulting JSON +-- to also be valid Java. +-- +-- AMBIGUOUS SITUATIONS DURING THE ENCODING +-- +-- During the encode, if a Lua table being encoded contains both string +-- and numeric keys, it fits neither JSON's idea of an object, nor its +-- idea of an array. To get around this, when any string key exists (or +-- when non-positive numeric keys exist), numeric keys are converted to +-- strings. +-- +-- For example, +-- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" })) +-- produces the JSON object +-- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"} +-- +-- To prohibit this conversion and instead make it an error condition, set +-- JSON.noKeyConversion = true +-- +-- +-- ENCODING JSON NULL VALUES +-- +-- Lua tables completely omit keys whose value is nil, so without special handling there's +-- no way to get a field in a JSON object with a null value. For example +-- JSON:encode({ username = "admin", password = nil }) +-- produces +-- {"username":"admin"} +-- +-- In order to actually produce +-- {"username":"admin", "password":null} +-- one can include a string value for a "null" field in the options table passed to encode().... +-- any Lua table entry with that value becomes null in the JSON output: +-- JSON:encode({ username = "admin", password = "xyzzy" }, nil, { null = "xyzzy" }) +-- produces +-- {"username":"admin", "password":null} +-- +-- Just be sure to use a string that is otherwise unlikely to appear in your data. +-- The string "\0" (a string with one null byte) may well be appropriate for many applications. +-- +-- The "null" options also applies to Lua tables that become JSON arrays. +-- JSON:encode({ "one", "two", nil, nil }) +-- produces +-- ["one","two"] +-- while +-- NULL = "\0" +-- JSON:encode({ "one", "two", NULL, NULL}, nil, { null = NULL }) +-- produces +-- ["one","two",null,null] +-- +-- +-- +-- +-- HANDLING LARGE AND/OR PRECISE NUMBERS +-- +-- +-- Without special handling, numbers in JSON can lose precision in Lua. +-- For example: +-- +-- T = JSON:decode('{ "small":12345, "big":12345678901234567890123456789, "precise":9876.67890123456789012345 }') +-- +-- print("small: ", type(T.small), T.small) +-- print("big: ", type(T.big), T.big) +-- print("precise: ", type(T.precise), T.precise) +-- +-- produces +-- +-- small: number 12345 +-- big: number 1.2345678901235e+28 +-- precise: number 9876.6789012346 +-- +-- Precision is lost with both 'big' and 'precise'. +-- +-- This package offers ways to try to handle this better (for some definitions of "better")... +-- +-- The most precise method is by setting the global: +-- +-- JSON.decodeNumbersAsObjects = true +-- +-- When this is set, numeric JSON data is encoded into Lua in a form that preserves the exact +-- JSON numeric presentation when re-encoded back out to JSON, or accessed in Lua as a string. +-- +-- (This is done by encoding the numeric data with a Lua table/metatable that returns +-- the possibly-imprecise numeric form when accessed numerically, but the original precise +-- representation when accessed as a string. You can also explicitly access +-- via JSON:forceString() and JSON:forceNumber()) +-- +-- Consider the example above, with this option turned on: +-- +-- JSON.decodeNumbersAsObjects = true +-- +-- T = JSON:decode('{ "small":12345, "big":12345678901234567890123456789, "precise":9876.67890123456789012345 }') +-- +-- print("small: ", type(T.small), T.small) +-- print("big: ", type(T.big), T.big) +-- print("precise: ", type(T.precise), T.precise) +-- +-- This now produces: +-- +-- small: table 12345 +-- big: table 12345678901234567890123456789 +-- precise: table 9876.67890123456789012345 +-- +-- However, within Lua you can still use the values (e.g. T.precise in the example above) in numeric +-- contexts. In such cases you'll get the possibly-imprecise numeric version, but in string contexts +-- and when the data finds its way to this package's encode() function, the original full-precision +-- representation is used. +-- +-- Even without using the JSON.decodeNumbersAsObjects option, you can encode numbers +-- in your Lua table that retain high precision upon encoding to JSON, by using the JSON:asNumber() +-- function: +-- +-- T = { +-- imprecise = 123456789123456789.123456789123456789, +-- precise = JSON:asNumber("123456789123456789.123456789123456789") +-- } +-- +-- print(JSON:encode_pretty(T)) +-- +-- This produces: +-- +-- { +-- "precise": 123456789123456789.123456789123456789, +-- "imprecise": 1.2345678912346e+17 +-- } +-- +-- +-- +-- A different way to handle big/precise JSON numbers is to have decode() merely return +-- the exact string representation of the number instead of the number itself. +-- This approach might be useful when the numbers are merely some kind of opaque +-- object identifier and you want to work with them in Lua as strings anyway. +-- +-- This approach is enabled by setting +-- +-- JSON.decodeIntegerStringificationLength = 10 +-- +-- The value is the number of digits (of the integer part of the number) at which to stringify numbers. +-- +-- Consider our previous example with this option set to 10: +-- +-- JSON.decodeIntegerStringificationLength = 10 +-- +-- T = JSON:decode('{ "small":12345, "big":12345678901234567890123456789, "precise":9876.67890123456789012345 }') +-- +-- print("small: ", type(T.small), T.small) +-- print("big: ", type(T.big), T.big) +-- print("precise: ", type(T.precise), T.precise) +-- +-- This produces: +-- +-- small: number 12345 +-- big: string 12345678901234567890123456789 +-- precise: number 9876.6789012346 +-- +-- The long integer of the 'big' field is at least JSON.decodeIntegerStringificationLength digits +-- in length, so it's converted not to a Lua integer but to a Lua string. Using a value of 0 or 1 ensures +-- that all JSON numeric data becomes strings in Lua. +-- +-- Note that unlike +-- JSON.decodeNumbersAsObjects = true +-- this stringification is simple and unintelligent: the JSON number simply becomes a Lua string, and that's the end of it. +-- If the string is then converted back to JSON, it's still a string. After running the code above, adding +-- print(JSON:encode(T)) +-- produces +-- {"big":"12345678901234567890123456789","precise":9876.6789012346,"small":12345} +-- which is unlikely to be desired. +-- +-- There's a comparable option for the length of the decimal part of a number: +-- +-- JSON.decodeDecimalStringificationLength +-- +-- This can be used alone or in conjunction with +-- +-- JSON.decodeIntegerStringificationLength +-- +-- to trip stringification on precise numbers with at least JSON.decodeIntegerStringificationLength digits after +-- the decimal point. +-- +-- This example: +-- +-- JSON.decodeIntegerStringificationLength = 10 +-- JSON.decodeDecimalStringificationLength = 5 +-- +-- T = JSON:decode('{ "small":12345, "big":12345678901234567890123456789, "precise":9876.67890123456789012345 }') +-- +-- print("small: ", type(T.small), T.small) +-- print("big: ", type(T.big), T.big) +-- print("precise: ", type(T.precise), T.precise) +-- +-- produces: +-- +-- small: number 12345 +-- big: string 12345678901234567890123456789 +-- precise: string 9876.67890123456789012345 +-- +-- +-- +-- +-- +-- SUMMARY OF METHODS YOU CAN OVERRIDE IN YOUR LOCAL LUA JSON OBJECT +-- +-- assert +-- onDecodeError +-- onDecodeOfNilError +-- onDecodeOfHTMLError +-- onTrailingGarbage +-- onEncodeError +-- +-- If you want to create a separate Lua JSON object with its own error handlers, +-- you can reload JSON.lua or use the :new() method. +-- +--------------------------------------------------------------------------- + +local default_pretty_indent = " " +local default_pretty_options = { pretty = true, align_keys = false, indent = default_pretty_indent } + +local isArray = { __tostring = function() return "JSON array" end } isArray.__index = isArray +local isObject = { __tostring = function() return "JSON object" end } isObject.__index = isObject + +function OBJDEF:newArray(tbl) + return setmetatable(tbl or {}, isArray) +end + +function OBJDEF:newObject(tbl) + return setmetatable(tbl or {}, isObject) +end + + + + +local function getnum(op) + return type(op) == 'number' and op or op.N +end + +local isNumber = { + __tostring = function(T) return T.S end, + __unm = function(op) return getnum(op) end, + + __concat = function(op1, op2) return tostring(op1) .. tostring(op2) end, + __add = function(op1, op2) return getnum(op1) + getnum(op2) end, + __sub = function(op1, op2) return getnum(op1) - getnum(op2) end, + __mul = function(op1, op2) return getnum(op1) * getnum(op2) end, + __div = function(op1, op2) return getnum(op1) / getnum(op2) end, + __mod = function(op1, op2) return getnum(op1) % getnum(op2) end, + __pow = function(op1, op2) return getnum(op1) ^ getnum(op2) end, + __lt = function(op1, op2) return getnum(op1) < getnum(op2) end, + __eq = function(op1, op2) return getnum(op1) == getnum(op2) end, + __le = function(op1, op2) return getnum(op1) <= getnum(op2) end, +} +isNumber.__index = isNumber + +function OBJDEF:asNumber(item) + + if getmetatable(item) == isNumber then + -- it's already a JSON number object. + return item + elseif type(item) == 'table' and type(item.S) == 'string' and type(item.N) == 'number' then + -- it's a number-object table that lost its metatable, so give it one + return setmetatable(item, isNumber) + else + -- the normal situation... given a number or a string representation of a number.... + local holder = { + S = tostring(item), -- S is the representation of the number as a string, which remains precise + N = tonumber(item), -- N is the number as a Lua number. + } + return setmetatable(holder, isNumber) + end +end + +-- +-- Given an item that might be a normal string or number, or might be an 'isNumber' object defined above, +-- return the string version. This shouldn't be needed often because the 'isNumber' object should autoconvert +-- to a string in most cases, but it's here to allow it to be forced when needed. +-- +function OBJDEF:forceString(item) + if type(item) == 'table' and type(item.S) == 'string' then + return item.S + else + return tostring(item) + end +end + +-- +-- Given an item that might be a normal string or number, or might be an 'isNumber' object defined above, +-- return the numeric version. +-- +function OBJDEF:forceNumber(item) + if type(item) == 'table' and type(item.N) == 'number' then + return item.N + else + return tonumber(item) + end +end + + +local function unicode_codepoint_as_utf8(codepoint) + -- + -- codepoint is a number + -- + if codepoint <= 127 then + return string.char(codepoint) + + elseif codepoint <= 2047 then + -- + -- 110yyyxx 10xxxxxx <-- useful notation from http://en.wikipedia.org/wiki/Utf8 + -- + local highpart = math.floor(codepoint / 0x40) + local lowpart = codepoint - (0x40 * highpart) + return string.char(0xC0 + highpart, + 0x80 + lowpart) + + elseif codepoint <= 65535 then + -- + -- 1110yyyy 10yyyyxx 10xxxxxx + -- + local highpart = math.floor(codepoint / 0x1000) + local remainder = codepoint - 0x1000 * highpart + local midpart = math.floor(remainder / 0x40) + local lowpart = remainder - 0x40 * midpart + + highpart = 0xE0 + highpart + midpart = 0x80 + midpart + lowpart = 0x80 + lowpart + + -- + -- Check for an invalid character (thanks Andy R. at Adobe). + -- See table 3.7, page 93, in http://www.unicode.org/versions/Unicode5.2.0/ch03.pdf#G28070 + -- + if ( highpart == 0xE0 and midpart < 0xA0 ) or + ( highpart == 0xED and midpart > 0x9F ) or + ( highpart == 0xF0 and midpart < 0x90 ) or + ( highpart == 0xF4 and midpart > 0x8F ) + then + return "?" + else + return string.char(highpart, + midpart, + lowpart) + end + + else + -- + -- 11110zzz 10zzyyyy 10yyyyxx 10xxxxxx + -- + local highpart = math.floor(codepoint / 0x40000) + local remainder = codepoint - 0x40000 * highpart + local midA = math.floor(remainder / 0x1000) + remainder = remainder - 0x1000 * midA + local midB = math.floor(remainder / 0x40) + local lowpart = remainder - 0x40 * midB + + return string.char(0xF0 + highpart, + 0x80 + midA, + 0x80 + midB, + 0x80 + lowpart) + end +end + +function OBJDEF:onDecodeError(message, text, location, etc) + if text then + if location then + message = string.format("%s at byte %d of: %s", message, location, text) + else + message = string.format("%s: %s", message, text) + end + end + + if etc ~= nil then + message = message .. " (" .. OBJDEF:encode(etc) .. ")" + end + + if self.assert then + self.assert(false, message) + else + assert(false, message) + end +end + +function OBJDEF:onTrailingGarbage(json_text, location, parsed_value, etc) + return self:onDecodeError("trailing garbage", json_text, location, etc) +end + +OBJDEF.onDecodeOfNilError = OBJDEF.onDecodeError +OBJDEF.onDecodeOfHTMLError = OBJDEF.onDecodeError + +function OBJDEF:onEncodeError(message, etc) + if etc ~= nil then + message = message .. " (" .. OBJDEF:encode(etc) .. ")" + end + + if self.assert then + self.assert(false, message) + else + assert(false, message) + end +end + +local function grok_number(self, text, start, options) + -- + -- Grab the integer part + -- + local integer_part = text:match('^-?[1-9]%d*', start) + or text:match("^-?0", start) + + if not integer_part then + self:onDecodeError("expected number", text, start, options.etc) + return nil, start -- in case the error method doesn't abort, return something sensible + end + + local i = start + integer_part:len() + + -- + -- Grab an optional decimal part + -- + local decimal_part = text:match('^%.%d+', i) or "" + + i = i + decimal_part:len() + + -- + -- Grab an optional exponential part + -- + local exponent_part = text:match('^[eE][-+]?%d+', i) or "" + + i = i + exponent_part:len() + + local full_number_text = integer_part .. decimal_part .. exponent_part + + if options.decodeNumbersAsObjects then + return OBJDEF:asNumber(full_number_text), i + end + + -- + -- If we're told to stringify under certain conditions, so do. + -- We punt a bit when there's an exponent by just stringifying no matter what. + -- I suppose we should really look to see whether the exponent is actually big enough one + -- way or the other to trip stringification, but I'll be lazy about it until someone asks. + -- + if (options.decodeIntegerStringificationLength + and + (integer_part:len() >= options.decodeIntegerStringificationLength or exponent_part:len() > 0)) + + or + + (options.decodeDecimalStringificationLength + and + (decimal_part:len() >= options.decodeDecimalStringificationLength or exponent_part:len() > 0)) + then + return full_number_text, i -- this returns the exact string representation seen in the original JSON + end + + + + local as_number = tonumber(full_number_text) + + if not as_number then + self:onDecodeError("bad number", text, start, options.etc) + return nil, start -- in case the error method doesn't abort, return something sensible + end + + return as_number, i +end + + +local function grok_string(self, text, start, options) + + if text:sub(start,start) ~= '"' then + self:onDecodeError("expected string's opening quote", text, start, options.etc) + return nil, start -- in case the error method doesn't abort, return something sensible + end + + local i = start + 1 -- +1 to bypass the initial quote + local text_len = text:len() + local VALUE = "" + while i <= text_len do + local c = text:sub(i,i) + if c == '"' then + return VALUE, i + 1 + end + if c ~= '\\' then + VALUE = VALUE .. c + i = i + 1 + elseif text:match('^\\b', i) then + VALUE = VALUE .. "\b" + i = i + 2 + elseif text:match('^\\f', i) then + VALUE = VALUE .. "\f" + i = i + 2 + elseif text:match('^\\n', i) then + VALUE = VALUE .. "\n" + i = i + 2 + elseif text:match('^\\r', i) then + VALUE = VALUE .. "\r" + i = i + 2 + elseif text:match('^\\t', i) then + VALUE = VALUE .. "\t" + i = i + 2 + else + local hex = text:match('^\\u([0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i) + if hex then + i = i + 6 -- bypass what we just read + + -- We have a Unicode codepoint. It could be standalone, or if in the proper range and + -- followed by another in a specific range, it'll be a two-code surrogate pair. + local codepoint = tonumber(hex, 16) + if codepoint >= 0xD800 and codepoint <= 0xDBFF then + -- it's a hi surrogate... see whether we have a following low + local lo_surrogate = text:match('^\\u([dD][cdefCDEF][0123456789aAbBcCdDeEfF][0123456789aAbBcCdDeEfF])', i) + if lo_surrogate then + i = i + 6 -- bypass the low surrogate we just read + codepoint = 0x2400 + (codepoint - 0xD800) * 0x400 + tonumber(lo_surrogate, 16) + else + -- not a proper low, so we'll just leave the first codepoint as is and spit it out. + end + end + VALUE = VALUE .. unicode_codepoint_as_utf8(codepoint) + + else + + -- just pass through what's escaped + VALUE = VALUE .. text:match('^\\(.)', i) + i = i + 2 + end + end + end + + self:onDecodeError("unclosed string", text, start, options.etc) + return nil, start -- in case the error method doesn't abort, return something sensible +end + +local function skip_whitespace(text, start) + + local _, match_end = text:find("^[ \n\r\t]+", start) -- [http://www.ietf.org/rfc/rfc4627.txt] Section 2 + if match_end then + return match_end + 1 + else + return start + end +end + +local grok_one -- assigned later + +local function grok_object(self, text, start, options) + + if text:sub(start,start) ~= '{' then + self:onDecodeError("expected '{'", text, start, options.etc) + return nil, start -- in case the error method doesn't abort, return something sensible + end + + local i = skip_whitespace(text, start + 1) -- +1 to skip the '{' + + local VALUE = self.strictTypes and self:newObject { } or { } + + if text:sub(i,i) == '}' then + return VALUE, i + 1 + end + local text_len = text:len() + while i <= text_len do + local key, new_i = grok_string(self, text, i, options) + + i = skip_whitespace(text, new_i) + + if text:sub(i, i) ~= ':' then + self:onDecodeError("expected colon", text, i, options.etc) + return nil, i -- in case the error method doesn't abort, return something sensible + end + + i = skip_whitespace(text, i + 1) + + local new_val, new_i = grok_one(self, text, i, options) + + VALUE[key] = new_val + + -- + -- Expect now either '}' to end things, or a ',' to allow us to continue. + -- + i = skip_whitespace(text, new_i) + + local c = text:sub(i,i) + + if c == '}' then + return VALUE, i + 1 + end + + if text:sub(i, i) ~= ',' then + self:onDecodeError("expected comma or '}'", text, i, options.etc) + return nil, i -- in case the error method doesn't abort, return something sensible + end + + i = skip_whitespace(text, i + 1) + end + + self:onDecodeError("unclosed '{'", text, start, options.etc) + return nil, start -- in case the error method doesn't abort, return something sensible +end + +local function grok_array(self, text, start, options) + if text:sub(start,start) ~= '[' then + self:onDecodeError("expected '['", text, start, options.etc) + return nil, start -- in case the error method doesn't abort, return something sensible + end + + local i = skip_whitespace(text, start + 1) -- +1 to skip the '[' + local VALUE = self.strictTypes and self:newArray { } or { } + if text:sub(i,i) == ']' then + return VALUE, i + 1 + end + + local VALUE_INDEX = 1 + + local text_len = text:len() + while i <= text_len do + local val, new_i = grok_one(self, text, i, options) + + -- can't table.insert(VALUE, val) here because it's a no-op if val is nil + VALUE[VALUE_INDEX] = val + VALUE_INDEX = VALUE_INDEX + 1 + + i = skip_whitespace(text, new_i) + + -- + -- Expect now either ']' to end things, or a ',' to allow us to continue. + -- + local c = text:sub(i,i) + if c == ']' then + return VALUE, i + 1 + end + if text:sub(i, i) ~= ',' then + self:onDecodeError("expected comma or ']'", text, i, options.etc) + return nil, i -- in case the error method doesn't abort, return something sensible + end + i = skip_whitespace(text, i + 1) + end + self:onDecodeError("unclosed '['", text, start, options.etc) + return nil, i -- in case the error method doesn't abort, return something sensible +end + + +grok_one = function(self, text, start, options) + -- Skip any whitespace + start = skip_whitespace(text, start) + + if start > text:len() then + self:onDecodeError("unexpected end of string", text, nil, options.etc) + return nil, start -- in case the error method doesn't abort, return something sensible + end + + if text:find('^"', start) then + return grok_string(self, text, start, options.etc) + + elseif text:find('^[-0123456789 ]', start) then + return grok_number(self, text, start, options) + + elseif text:find('^%{', start) then + return grok_object(self, text, start, options) + + elseif text:find('^%[', start) then + return grok_array(self, text, start, options) + + elseif text:find('^true', start) then + return true, start + 4 + + elseif text:find('^false', start) then + return false, start + 5 + + elseif text:find('^null', start) then + return nil, start + 4 + + else + self:onDecodeError("can't parse JSON", text, start, options.etc) + return nil, 1 -- in case the error method doesn't abort, return something sensible + end +end + +function OBJDEF:decode(text, etc, options) + -- + -- If the user didn't pass in a table of decode options, make an empty one. + -- + if type(options) ~= 'table' then + options = {} + end + + -- + -- If they passed in an 'etc' argument, stuff it into the options. + -- (If not, any 'etc' field in the options they passed in remains to be used) + -- + if etc ~= nil then + options.etc = etc + end + + + if type(self) ~= 'table' or self.__index ~= OBJDEF then + local error_message = "JSON:decode must be called in method format" + OBJDEF:onDecodeError(error_message, nil, nil, options.etc) + return nil, error_message -- in case the error method doesn't abort, return something sensible + end + + if text == nil then + local error_message = "nil passed to JSON:decode()" + self:onDecodeOfNilError(error_message, nil, nil, options.etc) + return nil, error_message -- in case the error method doesn't abort, return something sensible + + elseif type(text) ~= 'string' then + local error_message = "expected string argument to JSON:decode()" + self:onDecodeError(string.format("%s, got %s", error_message, type(text)), nil, nil, options.etc) + return nil, error_message -- in case the error method doesn't abort, return something sensible + end + + if text:match('^%s*$') then + -- an empty string is nothing, but not an error + return nil + end + + if text:match('^%s*<') then + -- Can't be JSON... we'll assume it's HTML + local error_message = "HTML passed to JSON:decode()" + self:onDecodeOfHTMLError(error_message, text, nil, options.etc) + return nil, error_message -- in case the error method doesn't abort, return something sensible + end + + -- + -- Ensure that it's not UTF-32 or UTF-16. + -- Those are perfectly valid encodings for JSON (as per RFC 4627 section 3), + -- but this package can't handle them. + -- + if text:sub(1,1):byte() == 0 or (text:len() >= 2 and text:sub(2,2):byte() == 0) then + local error_message = "JSON package groks only UTF-8, sorry" + self:onDecodeError(error_message, text, nil, options.etc) + return nil, error_message -- in case the error method doesn't abort, return something sensible + end + + -- + -- apply global options + -- + if options.decodeNumbersAsObjects == nil then + options.decodeNumbersAsObjects = self.decodeNumbersAsObjects + end + if options.decodeIntegerStringificationLength == nil then + options.decodeIntegerStringificationLength = self.decodeIntegerStringificationLength + end + if options.decodeDecimalStringificationLength == nil then + options.decodeDecimalStringificationLength = self.decodeDecimalStringificationLength + end + + -- + -- Finally, go parse it + -- + local success, value, next_i = pcall(grok_one, self, text, 1, options) + + if success then + + local error_message = nil + if next_i ~= #text + 1 then + -- something's left over after we parsed the first thing.... whitespace is allowed. + next_i = skip_whitespace(text, next_i) + + -- if we have something left over now, it's trailing garbage + if next_i ~= #text + 1 then + value, error_message = self:onTrailingGarbage(text, next_i, value, options.etc) + end + end + return value, error_message + + else + + -- If JSON:onDecodeError() didn't abort out of the pcall, we'll have received + -- the error message here as "value", so pass it along as an assert. + local error_message = value + if self.assert then + self.assert(false, error_message) + else + assert(false, error_message) + end + -- ...and if we're still here (because the assert didn't throw an error), + -- return a nil and throw the error message on as a second arg + return nil, error_message + + end +end + +local function backslash_replacement_function(c) + if c == "\n" then + return "\\n" + elseif c == "\r" then + return "\\r" + elseif c == "\t" then + return "\\t" + elseif c == "\b" then + return "\\b" + elseif c == "\f" then + return "\\f" + elseif c == '"' then + return '\\"' + elseif c == '\\' then + return '\\\\' + else + return string.format("\\u%04x", c:byte()) + end +end + +local chars_to_be_escaped_in_JSON_string + = '[' + .. '"' -- class sub-pattern to match a double quote + .. '%\\' -- class sub-pattern to match a backslash + .. '%z' -- class sub-pattern to match a null + .. '\001' .. '-' .. '\031' -- class sub-pattern to match control characters + .. ']' + + +local LINE_SEPARATOR_as_utf8 = unicode_codepoint_as_utf8(0x2028) +local PARAGRAPH_SEPARATOR_as_utf8 = unicode_codepoint_as_utf8(0x2029) +local function json_string_literal(value, options) + local newval = value:gsub(chars_to_be_escaped_in_JSON_string, backslash_replacement_function) + if options.stringsAreUtf8 then + -- + -- This feels really ugly to just look into a string for the sequence of bytes that we know to be a particular utf8 character, + -- but utf8 was designed purposefully to make this kind of thing possible. Still, feels dirty. + -- I'd rather decode the byte stream into a character stream, but it's not technically needed so + -- not technically worth it. + -- + newval = newval:gsub(LINE_SEPARATOR_as_utf8, '\\u2028'):gsub(PARAGRAPH_SEPARATOR_as_utf8,'\\u2029') + end + return '"' .. newval .. '"' +end + +local function object_or_array(self, T, etc) + -- + -- We need to inspect all the keys... if there are any strings, we'll convert to a JSON + -- object. If there are only numbers, it's a JSON array. + -- + -- If we'll be converting to a JSON object, we'll want to sort the keys so that the + -- end result is deterministic. + -- + local string_keys = { } + local number_keys = { } + local number_keys_must_be_strings = false + local maximum_number_key + + for key in pairs(T) do + if type(key) == 'string' then + table.insert(string_keys, key) + elseif type(key) == 'number' then + table.insert(number_keys, key) + if key <= 0 or key >= math.huge then + number_keys_must_be_strings = true + elseif not maximum_number_key or key > maximum_number_key then + maximum_number_key = key + end + else + self:onEncodeError("can't encode table with a key of type " .. type(key), etc) + end + end + + if #string_keys == 0 and not number_keys_must_be_strings then + -- + -- An empty table, or a numeric-only array + -- + if #number_keys > 0 then + return nil, maximum_number_key -- an array + elseif tostring(T) == "JSON array" then + return nil + elseif tostring(T) == "JSON object" then + return { } + else + -- have to guess, so we'll pick array, since empty arrays are likely more common than empty objects + return nil + end + end + + table.sort(string_keys) + + local map + if #number_keys > 0 then + -- + -- If we're here then we have either mixed string/number keys, or numbers inappropriate for a JSON array + -- It's not ideal, but we'll turn the numbers into strings so that we can at least create a JSON object. + -- + + if self.noKeyConversion then + self:onEncodeError("a table with both numeric and string keys could be an object or array; aborting", etc) + end + + -- + -- Have to make a shallow copy of the source table so we can remap the numeric keys to be strings + -- + map = { } + for key, val in pairs(T) do + map[key] = val + end + + table.sort(number_keys) + + -- + -- Throw numeric keys in there as strings + -- + for _, number_key in ipairs(number_keys) do + local string_key = tostring(number_key) + if map[string_key] == nil then + table.insert(string_keys , string_key) + map[string_key] = T[number_key] + else + self:onEncodeError("conflict converting table with mixed-type keys into a JSON object: key " .. number_key .. " exists both as a string and a number.", etc) + end + end + end + + return string_keys, nil, map +end + +-- +-- Encode +-- +-- 'options' is nil, or a table with possible keys: +-- +-- pretty -- If true, return a pretty-printed version. +-- +-- indent -- A string (usually of spaces) used to indent each nested level. +-- +-- align_keys -- If true, align all the keys when formatting a table. +-- +-- null -- If this exists with a string value, table elements with this value are output as JSON null. +-- +-- stringsAreUtf8 -- If true, consider Lua strings not as a sequence of bytes, but as a sequence of UTF-8 characters. +-- (Currently, the only practical effect of setting this option is that Unicode LINE and PARAGRAPH +-- separators, if found in a string, are encoded with a JSON escape instead of as raw UTF-8. +-- The JSON is valid either way, but encoding this way, apparently, allows the resulting JSON +-- to also be valid Java.) +-- +-- +local encode_value -- must predeclare because it calls itself +function encode_value(self, value, parents, etc, options, indent, for_key) + + -- + -- keys in a JSON object can never be null, so we don't even consider options.null when converting a key value + -- + if value == nil or (not for_key and options and options.null and value == options.null) then + return 'null' + + elseif type(value) == 'string' then + return json_string_literal(value, options) + + elseif type(value) == 'number' then + if value ~= value then + -- + -- NaN (Not a Number). + -- JSON has no NaN, so we have to fudge the best we can. This should really be a package option. + -- + return "null" + elseif value >= math.huge then + -- + -- Positive infinity. JSON has no INF, so we have to fudge the best we can. This should + -- really be a package option. Note: at least with some implementations, positive infinity + -- is both ">= math.huge" and "<= -math.huge", which makes no sense but that's how it is. + -- Negative infinity is properly "<= -math.huge". So, we must be sure to check the ">=" + -- case first. + -- + return "1e+9999" + elseif value <= -math.huge then + -- + -- Negative infinity. + -- JSON has no INF, so we have to fudge the best we can. This should really be a package option. + -- + return "-1e+9999" + else + return tostring(value) + end + + elseif type(value) == 'boolean' then + return tostring(value) + + elseif type(value) ~= 'table' then + self:onEncodeError("can't convert " .. type(value) .. " to JSON", etc) + + elseif getmetatable(value) == isNumber then + return tostring(value) + else + -- + -- A table to be converted to either a JSON object or array. + -- + local T = value + + if type(options) ~= 'table' then + options = {} + end + if type(indent) ~= 'string' then + indent = "" + end + + if parents[T] then + self:onEncodeError("table " .. tostring(T) .. " is a child of itself", etc) + else + parents[T] = true + end + + local result_value + + local object_keys, maximum_number_key, map = object_or_array(self, T, etc) + if maximum_number_key then + -- + -- An array... + -- + local ITEMS = { } + for i = 1, maximum_number_key do + table.insert(ITEMS, encode_value(self, T[i], parents, etc, options, indent)) + end + + if options.pretty then + result_value = "[ " .. table.concat(ITEMS, ", ") .. " ]" + else + result_value = "[" .. table.concat(ITEMS, ",") .. "]" + end + + elseif object_keys then + -- + -- An object + -- + local TT = map or T + + if options.pretty then + + local KEYS = { } + local max_key_length = 0 + for _, key in ipairs(object_keys) do + local encoded = encode_value(self, tostring(key), parents, etc, options, indent, true) + if options.align_keys then + max_key_length = math.max(max_key_length, #encoded) + end + table.insert(KEYS, encoded) + end + local key_indent = indent .. tostring(options.indent or "") + local subtable_indent = key_indent .. string.rep(" ", max_key_length) .. (options.align_keys and " " or "") + local FORMAT = "%s%" .. string.format("%d", max_key_length) .. "s: %s" + + local COMBINED_PARTS = { } + for i, key in ipairs(object_keys) do + local encoded_val = encode_value(self, TT[key], parents, etc, options, subtable_indent) + table.insert(COMBINED_PARTS, string.format(FORMAT, key_indent, KEYS[i], encoded_val)) + end + result_value = "{\n" .. table.concat(COMBINED_PARTS, ",\n") .. "\n" .. indent .. "}" + + else + + local PARTS = { } + for _, key in ipairs(object_keys) do + local encoded_val = encode_value(self, TT[key], parents, etc, options, indent) + local encoded_key = encode_value(self, tostring(key), parents, etc, options, indent, true) + table.insert(PARTS, string.format("%s:%s", encoded_key, encoded_val)) + end + result_value = "{" .. table.concat(PARTS, ",") .. "}" + + end + else + -- + -- An empty array/object... we'll treat it as an array, though it should really be an option + -- + result_value = "[]" + end + + parents[T] = false + return result_value + end +end + +local function top_level_encode(self, value, etc, options) + local val = encode_value(self, value, {}, etc, options) + if val == nil then + --PRIVATE("may need to revert to the previous public verison if I can't figure out what the guy wanted") + return val + else + return val + end +end + +function OBJDEF:encode(value, etc, options) + if type(self) ~= 'table' or self.__index ~= OBJDEF then + OBJDEF:onEncodeError("JSON:encode must be called in method format", etc) + end + + -- + -- If the user didn't pass in a table of decode options, make an empty one. + -- + if type(options) ~= 'table' then + options = {} + end + + return top_level_encode(self, value, etc, options) +end + +function OBJDEF:encode_pretty(value, etc, options) + if type(self) ~= 'table' or self.__index ~= OBJDEF then + OBJDEF:onEncodeError("JSON:encode_pretty must be called in method format", etc) + end + + -- + -- If the user didn't pass in a table of decode options, use the default pretty ones + -- + if type(options) ~= 'table' then + options = default_pretty_options + end + + return top_level_encode(self, value, etc, options) +end + +function OBJDEF.__tostring() + return "JSON encode/decode package" +end + +OBJDEF.__index = OBJDEF + +function OBJDEF:new(args) + local new = { } + + if args then + for key, val in pairs(args) do + new[key] = val + end + end + + return setmetatable(new, OBJDEF) +end + +return OBJDEF:new() + +-- +-- Version history: +-- +-- 20161109.21 Oops, had a small boo-boo in the previous update. +-- +-- 20161103.20 Used to silently ignore trailing garbage when decoding. Now fails via JSON:onTrailingGarbage() +-- http://seriot.ch/parsing_json.php +-- +-- Built-in error message about "expected comma or ']'" had mistakenly referred to '[' +-- +-- Updated the built-in error reporting to refer to bytes rather than characters. +-- +-- The decode() method no longer assumes that error handlers abort. +-- +-- Made the VERSION string a string instead of a number +-- + +-- 20160916.19 Fixed the isNumber.__index assignment (thanks to Jack Taylor) +-- +-- 20160730.18 Added JSON:forceString() and JSON:forceNumber() +-- +-- 20160728.17 Added concatenation to the metatable for JSON:asNumber() +-- +-- 20160709.16 Could crash if not passed an options table (thanks jarno heikkinen ). +-- +-- Made JSON:asNumber() a bit more resilient to being passed the results of itself. +-- +-- 20160526.15 Added the ability to easily encode null values in JSON, via the new "null" encoding option. +-- (Thanks to Adam B for bringing up the issue.) +-- +-- Added some support for very large numbers and precise floats via +-- JSON.decodeNumbersAsObjects +-- JSON.decodeIntegerStringificationLength +-- JSON.decodeDecimalStringificationLength +-- +-- Added the "stringsAreUtf8" encoding option. (Hat tip to http://lua-users.org/wiki/JsonModules ) +-- +-- 20141223.14 The encode_pretty() routine produced fine results for small datasets, but isn't really +-- appropriate for anything large, so with help from Alex Aulbach I've made the encode routines +-- more flexible, and changed the default encode_pretty() to be more generally useful. +-- +-- Added a third 'options' argument to the encode() and encode_pretty() routines, to control +-- how the encoding takes place. +-- +-- Updated docs to add assert() call to the loadfile() line, just as good practice so that +-- if there is a problem loading JSON.lua, the appropriate error message will percolate up. +-- +-- 20140920.13 Put back (in a way that doesn't cause warnings about unused variables) the author string, +-- so that the source of the package, and its version number, are visible in compiled copies. +-- +-- 20140911.12 Minor lua cleanup. +-- Fixed internal reference to 'JSON.noKeyConversion' to reference 'self' instead of 'JSON'. +-- (Thanks to SmugMug's David Parry for these.) +-- +-- 20140418.11 JSON nulls embedded within an array were being ignored, such that +-- ["1",null,null,null,null,null,"seven"], +-- would return +-- {1,"seven"} +-- It's now fixed to properly return +-- {1, nil, nil, nil, nil, nil, "seven"} +-- Thanks to "haddock" for catching the error. +-- +-- 20140116.10 The user's JSON.assert() wasn't always being used. Thanks to "blue" for the heads up. +-- +-- 20131118.9 Update for Lua 5.3... it seems that tostring(2/1) produces "2.0" instead of "2", +-- and this caused some problems. +-- +-- 20131031.8 Unified the code for encode() and encode_pretty(); they had been stupidly separate, +-- and had of course diverged (encode_pretty didn't get the fixes that encode got, so +-- sometimes produced incorrect results; thanks to Mattie for the heads up). +-- +-- Handle encoding tables with non-positive numeric keys (unlikely, but possible). +-- +-- If a table has both numeric and string keys, or its numeric keys are inappropriate +-- (such as being non-positive or infinite), the numeric keys are turned into +-- string keys appropriate for a JSON object. So, as before, +-- JSON:encode({ "one", "two", "three" }) +-- produces the array +-- ["one","two","three"] +-- but now something with mixed key types like +-- JSON:encode({ "one", "two", "three", SOMESTRING = "some string" })) +-- instead of throwing an error produces an object: +-- {"1":"one","2":"two","3":"three","SOMESTRING":"some string"} +-- +-- To maintain the prior throw-an-error semantics, set +-- JSON.noKeyConversion = true +-- +-- 20131004.7 Release under a Creative Commons CC-BY license, which I should have done from day one, sorry. +-- +-- 20130120.6 Comment update: added a link to the specific page on my blog where this code can +-- be found, so that folks who come across the code outside of my blog can find updates +-- more easily. +-- +-- 20111207.5 Added support for the 'etc' arguments, for better error reporting. +-- +-- 20110731.4 More feedback from David Kolf on how to make the tests for Nan/Infinity system independent. +-- +-- 20110730.3 Incorporated feedback from David Kolf at http://lua-users.org/wiki/JsonModules: +-- +-- * When encoding lua for JSON, Sparse numeric arrays are now handled by +-- spitting out full arrays, such that +-- JSON:encode({"one", "two", [10] = "ten"}) +-- returns +-- ["one","two",null,null,null,null,null,null,null,"ten"] +-- +-- In 20100810.2 and earlier, only up to the first non-null value would have been retained. +-- +-- * When encoding lua for JSON, numeric value NaN gets spit out as null, and infinity as "1+e9999". +-- Version 20100810.2 and earlier created invalid JSON in both cases. +-- +-- * Unicode surrogate pairs are now detected when decoding JSON. +-- +-- 20100810.2 added some checking to ensure that an invalid Unicode character couldn't leak in to the UTF-8 encoding +-- +-- 20100731.1 initial public release +-- diff --git a/src/base/jsonwrapper.lua b/src/base/jsonwrapper.lua new file mode 100644 index 00000000..57d4aa9b --- /dev/null +++ b/src/base/jsonwrapper.lua @@ -0,0 +1,46 @@ +-- +-- jsonwrapper.lua +-- Provides JSON encoding and decoding API by wrapping a third-party JSON library +-- Copyright (c) 2017 Jason Perkins and the Premake project +-- + + json = {} + + local implementation = dofile('json.lua') + local err + + function implementation.assert(condition, message) + if not condition then + err = message + end + + -- The JSON library we're using assumes that encode error handlers will + -- abort on error. It doesn't have the same assumption for decode error + -- handlers, but we're using this same function for both. + + assert(condition, message) + end + + function json.encode(value) + err = nil + + local success, result = pcall(implementation.encode, implementation, value) + + if not success then + return nil, err + end + + return result + end + + function json.decode(value) + err = nil + + local success, result = pcall(implementation.decode, implementation, value) + + if not success then + return nil, err + end + + return result + end diff --git a/tests/_tests.lua b/tests/_tests.lua index 1ece5ecc..7773001f 100644 --- a/tests/_tests.lua +++ b/tests/_tests.lua @@ -18,6 +18,7 @@ return { "base/test_uuid.lua", "base/test_versions.lua", "base/test_http.lua", + "base/test_json.lua", -- Workspace object tests "workspace/test_eachconfig.lua", diff --git a/tests/base/test_json.lua b/tests/base/test_json.lua new file mode 100644 index 00000000..abc71bdc --- /dev/null +++ b/tests/base/test_json.lua @@ -0,0 +1,32 @@ +-- +-- tests/base/test_json.lua +-- Tests the json API +-- Copyright (c) 2017 Jason Perkins and the Premake project +-- + + local p = premake + + local suite = test.declare("premake_json") + + function suite.json_encode() + local result = json.encode({foo = "bar"}) + result = result:gsub('%s*', ''), + test.isequal(result, '{"foo":"bar"}') + end + + function suite.json_decode() + local result = json.decode('{ "foo": "bar" }') + test.isequal(result, { foo = "bar" }) + end + + function suite.json_encode_error() + local result, err = json.encode({ fubar = function() end }) + test.isnil(result) + test.isequal(type(err), "string") + end + + function suite.json_decode_error() + local result, err = json.decode("fubar string") + test.isnil(result) + test.isequal(type(err), "string") + end From a079f1cd103cf68b1e61b303e08fff26d49f0238 Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Tue, 4 Apr 2017 18:05:56 +0300 Subject: [PATCH 06/59] Update .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index cfbed3f0..c2f14900 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,8 @@ Makefile *.ncb *.vcproj* *.vcxproj* +*.VC.opendb +*.VC.db *.opensdf *.workspace *.project From f3dae94acabf7e8ab6c0c2330806cdc2aeda885e Mon Sep 17 00:00:00 2001 From: Jason Stewart Date: Thu, 6 Apr 2017 07:51:04 -0400 Subject: [PATCH 07/59] Fix VS2013 and older always rebuilding when debug symbols explicitly disabled Visual Studio versions 2013 and older have an issue with DebugInformationFormat set to None. The project will always be out of date and thus always rebuild. The workaround is to leave the DebugInformationFormat field blank. https://connect.microsoft.com/VisualStudio/feedback/details/833494/project-with-debug-information-disabled-always-rebuilds VS2015 and newer do not have this issue. --- src/actions/vstudio/vs2010_vcxproj.lua | 9 +++++++- .../vstudio/vc2010/test_compile_settings.lua | 21 ++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index 656e5cb6..0b160374 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -1262,7 +1262,14 @@ m.element("DebugInformationFormat", nil, value) elseif cfg.symbols == p.OFF then - m.element("DebugInformationFormat", nil, "None") + -- leave field blank for vs2013 and older to workaround bug + if _ACTION < "vs2015" then + value = "" + else + value = "None" + end + + m.element("DebugInformationFormat", nil, value) end end diff --git a/tests/actions/vstudio/vc2010/test_compile_settings.lua b/tests/actions/vstudio/vc2010/test_compile_settings.lua index 3b531913..6e20a6f7 100644 --- a/tests/actions/vstudio/vc2010/test_compile_settings.lua +++ b/tests/actions/vstudio/vc2010/test_compile_settings.lua @@ -790,11 +790,31 @@ -- -- Check handling of the explicitly disabling symbols. +-- Note: VS2013 and older have a bug with setting +-- DebugInformationFormat to None. The workaround +-- is to leave the field blank. -- function suite.onNoSymbols() symbols 'Off' prepare() test.capture [[ + + NotUsing + Level3 + + Disabled + ]] + end + + +-- +-- VS2015 and newer can use DebugInformationFormat None. +-- + function suite.onNoSymbolsVS2015() + symbols 'Off' + premake.action.set("vs2015") + prepare() + test.capture [[ NotUsing Level3 @@ -804,7 +824,6 @@ end - -- -- Check handling of the stringpooling api -- From d2da31bbcc8c7aa1a809f10a7dbef4e7f2986a3e Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Fri, 7 Apr 2017 00:10:43 +1000 Subject: [PATCH 08/59] Generated project files are now correctly located beside script --- src/base/oven.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/base/oven.lua b/src/base/oven.lua index 939a8755..eb1ac786 100644 --- a/src/base/oven.lua +++ b/src/base/oven.lua @@ -235,7 +235,7 @@ -- location. Any path tokens which are expanded in non-path fields -- are made relative to this, ensuring a portable generated project. - self.location = self.location or wks.location or self.basedir + self.location = self.location or self.basedir context.basedir(self, self.location) -- This bit could use some work: create a canonical set of configurations From 690dee040513f364b570b8906b3ca08627bed4e7 Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Mon, 10 Apr 2017 01:41:18 +1000 Subject: [PATCH 09/59] Fixed issue with Clang not actually supporting floatingpoint 'strict' --- src/tools/clang.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/clang.lua b/src/tools/clang.lua index 282f7d28..2928fcb5 100644 --- a/src/tools/clang.lua +++ b/src/tools/clang.lua @@ -44,7 +44,9 @@ clang.shared = { architecture = gcc.shared.architecture, flags = gcc.shared.flags, - floatingpoint = gcc.shared.floatingpoint, + floatingpoint = { + Fast = "-ffast-math", + }, strictaliasing = gcc.shared.strictaliasing, optimize = { Off = "-O0", From a24f5c1e9bc8c0656927a9e47baeb0f72672e384 Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Mon, 10 Apr 2017 01:51:30 +1000 Subject: [PATCH 10/59] Fixed issue where VS2010+ projects didn't support floatingpoint 'Default' --- src/actions/vstudio/vs2010_vcxproj.lua | 2 +- tests/actions/vstudio/vc2010/test_floatingpoint.lua | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index 0b160374..c4be0603 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -1352,7 +1352,7 @@ function m.floatingPointModel(cfg) - if cfg.floatingpoint then + if cfg.floatingpoint and cfg.floatingpoint ~= "Default" then m.element("FloatingPointModel", nil, cfg.floatingpoint) end end diff --git a/tests/actions/vstudio/vc2010/test_floatingpoint.lua b/tests/actions/vstudio/vc2010/test_floatingpoint.lua index abd65b59..1816ff24 100644 --- a/tests/actions/vstudio/vc2010/test_floatingpoint.lua +++ b/tests/actions/vstudio/vc2010/test_floatingpoint.lua @@ -30,7 +30,7 @@ function suite.floatingPoint_onFloatFast() - flags "FloatFast" + floatingpoint "fast" prepare() test.capture [[ Fast @@ -38,12 +38,15 @@ end function suite.floatingPoint_onFloatStrict() - flags "FloatStrict" + floatingpoint "strict" prepare() test.capture [[ Strict ]] end - - + function suite.floatingPoint_onDefault() + floatingpoint "Default" + prepare() + test.isemptycapture() + end From 87e001d4e9190dd2117b64c13baf225c4baf033f Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Mon, 10 Apr 2017 13:52:36 +0300 Subject: [PATCH 11/59] Add string.escapepattern function --- src/base/string.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/base/string.lua b/src/base/string.lua index afea319e..0a1a537d 100644 --- a/src/base/string.lua +++ b/src/base/string.lua @@ -91,3 +91,13 @@ return self .. "s" end end + + + +--- +-- Returns the string escaped for Lua patterns. +--- + + function string.escapepattern(s) + return s:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%0") + end From c619314a01972585f6d495b85afccd5c238737e9 Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Mon, 10 Apr 2017 14:37:47 +0300 Subject: [PATCH 12/59] Add tests for string.escapepattern --- tests/test_string.lua | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/test_string.lua b/tests/test_string.lua index 33d4452b..08a931f3 100644 --- a/tests/test_string.lua +++ b/tests/test_string.lua @@ -70,3 +70,31 @@ function suite.startswith_OnEmptyNeedle() test.istrue(string.startswith("Abcdef", "")) end + + + +-- +-- string.escapepattern() tests +-- + + function suite.escapepattern_escapes() + test.isequal("boost_filesystem%-vc140%.1%.61%.0%.0", string.escapepattern("boost_filesystem-vc140.1.61.0.0")) + test.isequal("footage/down/temp/cars_%[100%]_upper/cars_%[100%]_upper%.exr", string.escapepattern("footage/down/temp/cars_[100]_upper/cars_[100]_upper.exr")) + end + + function suite.escapepattern_doesntEscape() + local s = '' + test.isequal(s, s:escapepattern()) + + s = 'lorem ipsum dolor sit amet' + test.isequal(s, s:escapepattern()) + + s = 'forward/slashes/foo/bar' + test.isequal(s, s:escapepattern()) + + s = '\\back\\slashes' + test.isequal(s, s:escapepattern()) + + s = 'new\nlines' + test.isequal(s, s:escapepattern()) + end From af7187407a5f1c1ed93ea492b262d96b5f8781a2 Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Tue, 11 Apr 2017 15:10:46 +0300 Subject: [PATCH 13/59] Update curl to 7.53.1 --- contrib/curl/include/README | 2 +- contrib/curl/include/curl/curl.h | 115 +- contrib/curl/include/curl/curlver.h | 10 +- contrib/curl/include/curl/easy.h | 4 +- contrib/curl/include/curl/multi.h | 6 +- contrib/curl/include/curl/stdcheaders.h | 6 +- contrib/curl/include/curl/typecheck-gcc.h | 58 +- contrib/curl/lib/.gitignore | 1 - contrib/curl/lib/CMakeLists.txt | 5 + contrib/curl/lib/Makefile.am | 4 +- contrib/curl/lib/Makefile.inc | 12 +- contrib/curl/lib/Makefile.m32 | 4 + contrib/curl/lib/Makefile.netware | 2 +- contrib/curl/lib/Makefile.vc6 | 689 --------- contrib/curl/lib/amigaos.c | 2 +- contrib/curl/lib/asyn-ares.c | 20 +- contrib/curl/lib/asyn-thread.c | 48 +- contrib/curl/lib/asyn.h | 2 +- contrib/curl/lib/base64.c | 13 +- contrib/curl/lib/checksrc.pl | 67 +- contrib/curl/lib/config-amigaos.h | 4 +- contrib/curl/lib/config-symbian.h | 6 +- contrib/curl/lib/conncache.c | 13 +- contrib/curl/lib/connect.c | 191 +-- contrib/curl/lib/connect.h | 57 +- contrib/curl/lib/content_encoding.c | 29 +- contrib/curl/lib/cookie.c | 177 ++- contrib/curl/lib/cookie.h | 16 +- contrib/curl/lib/curl_addrinfo.c | 87 +- contrib/curl/lib/curl_addrinfo.h | 12 +- contrib/curl/lib/curl_base64.h | 4 +- contrib/curl/lib/curl_config.h.cmake | 23 +- contrib/curl/lib/curl_des.c | 2 +- contrib/curl/lib/curl_endian.c | 18 +- contrib/curl/lib/curl_endian.h | 18 +- contrib/curl/lib/curl_gethostname.c | 8 +- contrib/curl/lib/curl_gssapi.c | 6 +- contrib/curl/lib/curl_gssapi.h | 4 +- contrib/curl/lib/curl_hmac.h | 26 +- contrib/curl/lib/curl_ntlm_core.c | 49 +- contrib/curl/lib/curl_ntlm_core.h | 4 +- contrib/curl/lib/curl_ntlm_wb.c | 15 +- contrib/curl/lib/curl_sasl.c | 36 +- contrib/curl/lib/curl_sasl.h | 2 +- contrib/curl/lib/curl_sec.h | 16 +- contrib/curl/lib/curl_setup.h | 37 +- contrib/curl/lib/curl_sspi.c | 63 +- contrib/curl/lib/curl_threads.c | 5 +- contrib/curl/lib/curl_threads.h | 5 +- contrib/curl/lib/curlx.h | 13 +- contrib/curl/lib/dict.c | 29 +- contrib/curl/lib/easy.c | 111 +- contrib/curl/lib/easyif.h | 4 +- contrib/curl/lib/escape.c | 54 +- contrib/curl/lib/escape.h | 2 +- contrib/curl/lib/file.c | 31 +- contrib/curl/lib/formdata.c | 122 +- contrib/curl/lib/formdata.h | 7 +- contrib/curl/lib/ftp.c | 372 ++--- contrib/curl/lib/ftp.h | 10 +- contrib/curl/lib/ftplistparser.c | 11 +- contrib/curl/lib/getenv.c | 3 +- contrib/curl/lib/getinfo.c | 72 +- contrib/curl/lib/getinfo.h | 4 +- contrib/curl/lib/gopher.c | 39 +- contrib/curl/lib/hash.c | 6 +- contrib/curl/lib/hash.h | 15 +- contrib/curl/lib/hmac.c | 10 +- contrib/curl/lib/hostasyn.c | 2 +- contrib/curl/lib/hostcheck.c | 23 +- contrib/curl/lib/hostip.c | 29 +- contrib/curl/lib/hostip.h | 30 +- contrib/curl/lib/hostip4.c | 2 +- contrib/curl/lib/hostip6.c | 14 +- contrib/curl/lib/hostsyn.c | 8 +- contrib/curl/lib/http.c | 503 +++--- contrib/curl/lib/http.h | 13 +- contrib/curl/lib/http2.c | 513 ++++-- contrib/curl/lib/http2.h | 16 +- contrib/curl/lib/http_chunks.c | 16 +- contrib/curl/lib/http_digest.c | 28 +- contrib/curl/lib/http_digest.h | 2 +- contrib/curl/lib/http_negotiate.c | 21 +- contrib/curl/lib/http_negotiate.h | 2 +- contrib/curl/lib/http_ntlm.c | 8 +- contrib/curl/lib/http_proxy.c | 550 ++++--- contrib/curl/lib/http_proxy.h | 4 +- contrib/curl/lib/if2ip.c | 10 +- contrib/curl/lib/imap.c | 74 +- contrib/curl/lib/imap.h | 4 +- contrib/curl/lib/inet_ntop.c | 6 +- contrib/curl/lib/inet_pton.c | 8 +- contrib/curl/lib/krb5.c | 16 +- contrib/curl/lib/ldap.c | 103 +- contrib/curl/lib/libcurl.def | 53 - contrib/curl/lib/libcurl.rc | 8 +- contrib/curl/lib/md4.c | 3 +- contrib/curl/lib/md5.c | 9 +- contrib/curl/lib/memdebug.c | 4 +- contrib/curl/lib/mk-ca-bundle.pl | 173 ++- contrib/curl/lib/mk-ca-bundle.vbs | 261 +++- contrib/curl/lib/mprintf.c | 51 +- contrib/curl/lib/multi.c | 475 +++--- contrib/curl/lib/multihandle.h | 12 +- contrib/curl/lib/multiif.h | 13 +- contrib/curl/lib/netrc.c | 18 +- contrib/curl/lib/non-ascii.c | 26 +- contrib/curl/lib/non-ascii.h | 16 +- contrib/curl/lib/nwlib.c | 10 +- contrib/curl/lib/nwos.c | 8 +- contrib/curl/lib/openldap.c | 10 +- contrib/curl/lib/parsedate.c | 20 +- contrib/curl/lib/pingpong.c | 25 +- contrib/curl/lib/pingpong.h | 2 +- contrib/curl/lib/pipeline.c | 47 +- contrib/curl/lib/pipeline.h | 18 +- contrib/curl/lib/pop3.c | 61 +- contrib/curl/lib/pop3.h | 4 +- contrib/curl/lib/progress.c | 105 +- contrib/curl/lib/progress.h | 20 +- contrib/curl/lib/rand.c | 132 ++ contrib/curl/lib/{strequal.h => rand.h} | 30 +- contrib/curl/lib/rtsp.c | 60 +- contrib/curl/lib/security.c | 30 +- contrib/curl/lib/select.c | 37 +- contrib/curl/lib/select.h | 11 +- contrib/curl/lib/sendf.c | 39 +- contrib/curl/lib/sendf.h | 8 +- contrib/curl/lib/setup-os400.h | 52 +- contrib/curl/lib/setup-vms.h | 127 +- contrib/curl/lib/share.c | 13 +- contrib/curl/lib/share.h | 8 +- contrib/curl/lib/sigpipe.h | 4 +- contrib/curl/lib/smb.c | 58 +- contrib/curl/lib/smtp.c | 67 +- contrib/curl/lib/smtp.h | 4 +- contrib/curl/lib/socks.c | 169 +- contrib/curl/lib/socks.h | 5 +- contrib/curl/lib/socks_gssapi.c | 28 +- contrib/curl/lib/socks_sspi.c | 17 +- contrib/curl/lib/speedcheck.c | 10 +- contrib/curl/lib/speedcheck.h | 4 +- contrib/curl/lib/ssh.c | 148 +- contrib/curl/lib/ssh.h | 2 +- contrib/curl/lib/{rawstr.c => strcase.c} | 38 +- contrib/curl/lib/{rawstr.h => strcase.h} | 26 +- contrib/curl/lib/strdup.c | 27 +- contrib/curl/lib/strdup.h | 5 +- contrib/curl/lib/strequal.c | 79 - contrib/curl/lib/strerror.c | 119 +- contrib/curl/lib/strerror.h | 4 +- contrib/curl/lib/strtoofft.c | 4 +- contrib/curl/lib/system_win32.c | 209 ++- contrib/curl/lib/system_win32.h | 22 + contrib/curl/lib/telnet.c | 69 +- contrib/curl/lib/tftp.c | 59 +- contrib/curl/lib/timeval.c | 6 +- contrib/curl/lib/timeval.h | 6 +- contrib/curl/lib/transfer.c | 140 +- contrib/curl/lib/transfer.h | 18 +- contrib/curl/lib/url.c | 1545 ++++++++++++------- contrib/curl/lib/url.h | 41 +- contrib/curl/lib/urldata.h | 214 ++- contrib/curl/lib/vauth/cleartext.c | 32 +- contrib/curl/lib/vauth/cram.c | 2 +- contrib/curl/lib/vauth/digest.c | 69 +- contrib/curl/lib/vauth/digest_sspi.c | 321 ++-- contrib/curl/lib/vauth/krb5_gssapi.c | 18 +- contrib/curl/lib/vauth/krb5_sspi.c | 26 +- contrib/curl/lib/vauth/ntlm.c | 36 +- contrib/curl/lib/vauth/ntlm.h | 2 +- contrib/curl/lib/vauth/ntlm_sspi.c | 25 +- contrib/curl/lib/vauth/oauth2.c | 2 +- contrib/curl/lib/vauth/spnego_gssapi.c | 20 +- contrib/curl/lib/vauth/spnego_sspi.c | 34 +- contrib/curl/lib/vauth/vauth.c | 41 + contrib/curl/lib/vauth/vauth.h | 49 +- contrib/curl/lib/version.c | 17 +- contrib/curl/lib/vtls/axtls.c | 132 +- contrib/curl/lib/vtls/axtls.h | 8 +- contrib/curl/lib/vtls/cyassl.c | 211 ++- contrib/curl/lib/vtls/cyassl.h | 10 +- contrib/curl/lib/vtls/darwinssl.c | 569 ++++--- contrib/curl/lib/vtls/darwinssl.h | 6 +- contrib/curl/lib/vtls/gskit.c | 392 ++++- contrib/curl/lib/vtls/gskit.h | 7 +- contrib/curl/lib/vtls/gtls.c | 361 +++-- contrib/curl/lib/vtls/gtls.h | 15 +- contrib/curl/lib/vtls/mbedtls.c | 245 ++- contrib/curl/lib/vtls/mbedtls.h | 11 +- contrib/curl/lib/vtls/nss.c | 364 +++-- contrib/curl/lib/vtls/nssg.h | 15 +- contrib/curl/lib/vtls/openssl.c | 731 +++++---- contrib/curl/lib/vtls/openssl.h | 17 +- contrib/curl/lib/vtls/polarssl.c | 233 +-- contrib/curl/lib/vtls/polarssl.h | 3 +- contrib/curl/lib/vtls/polarssl_threadlock.c | 4 +- contrib/curl/lib/vtls/schannel.c | 377 +++-- contrib/curl/lib/vtls/schannel.h | 7 +- contrib/curl/lib/vtls/vtls.c | 370 +++-- contrib/curl/lib/vtls/vtls.h | 99 +- contrib/curl/lib/wildcard.h | 2 +- contrib/curl/lib/x509asn1.c | 210 +-- contrib/curl/lib/x509asn1.h | 30 +- contrib/curl/premake5.lua | 1 + 205 files changed, 8818 insertions(+), 6375 deletions(-) delete mode 100644 contrib/curl/lib/Makefile.vc6 delete mode 100644 contrib/curl/lib/libcurl.def create mode 100644 contrib/curl/lib/rand.c rename contrib/curl/lib/{strequal.h => rand.h} (55%) rename contrib/curl/lib/{rawstr.c => strcase.c} (80%) rename contrib/curl/lib/{rawstr.h => strcase.h} (64%) delete mode 100644 contrib/curl/lib/strequal.c diff --git a/contrib/curl/include/README b/contrib/curl/include/README index 3e52a1d0..6eb73b2b 100644 --- a/contrib/curl/include/README +++ b/contrib/curl/include/README @@ -37,7 +37,7 @@ The following notes apply to libcurl version 7.19.0 and later. also distribute along with it the generated curl/curlbuild.h which has been used to compile it. Otherwise the library will be of no use for the users of the library that you have built. It is _your_ responsibility to provide this - file. No one at the cURL project can know how you have built the library. + file. No one at the curl project can know how you have built the library. * File curl/curlbuild.h includes platform and configuration dependent info, and must not be modified by anyone. Configure script generates it for you. diff --git a/contrib/curl/include/curl/curl.h b/contrib/curl/include/curl/curl.h index 57e716b3..467bb024 100644 --- a/contrib/curl/include/curl/curl.h +++ b/contrib/curl/include/curl/curl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -30,6 +30,10 @@ * https://cool.haxx.se/mailman/listinfo/curl-library/ */ +#ifdef CURL_NO_OLDIES +#define CURL_STRICTER +#endif + #include "curlver.h" /* libcurl version defines */ #include "curlbuild.h" /* libcurl build definitions */ #include "curlrules.h" /* libcurl rules enforcement */ @@ -91,7 +95,13 @@ extern "C" { #endif +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_easy CURL; +typedef struct Curl_share CURLSH; +#else typedef void CURL; +typedef void CURLSH; +#endif /* * libcurl external API function linkage decorations. @@ -133,7 +143,7 @@ struct curl_httppost { char *buffer; /* pointer to allocated buffer contents */ long bufferlength; /* length of buffer field */ char *contenttype; /* Content-Type */ - struct curl_slist* contentheader; /* list of extra headers for this form */ + struct curl_slist *contentheader; /* list of extra headers for this form */ struct curl_httppost *more; /* if one field name has more than one file, this link should link to following files */ @@ -183,6 +193,11 @@ typedef int (*curl_xferinfo_callback)(void *clientp, curl_off_t ultotal, curl_off_t ulnow); +#ifndef CURL_MAX_READ_SIZE + /* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */ +#define CURL_MAX_READ_SIZE 524288 +#endif + #ifndef CURL_MAX_WRITE_SIZE /* Tests have proven that 20K is a very bad buffer size for uploads on Windows, while 16K for some odd reason performed a lot better. @@ -260,7 +275,7 @@ struct curl_fileinfo { unsigned int flags; /* used internally */ - char * b_data; + char *b_data; size_t b_size; size_t b_used; }; @@ -425,7 +440,7 @@ typedef enum { CURLE_COULDNT_RESOLVE_PROXY, /* 5 */ CURLE_COULDNT_RESOLVE_HOST, /* 6 */ CURLE_COULDNT_CONNECT, /* 7 */ - CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */ + CURLE_WEIRD_SERVER_REPLY, /* 8 */ CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server due to lack of access - when login fails this is not returned. */ @@ -469,7 +484,7 @@ typedef enum { CURLE_LDAP_CANNOT_BIND, /* 38 */ CURLE_LDAP_SEARCH_FAILED, /* 39 */ CURLE_OBSOLETE40, /* 40 - NOT USED */ - CURLE_FUNCTION_NOT_FOUND, /* 41 */ + CURLE_FUNCTION_NOT_FOUND, /* 41 - NOT USED starting with 7.53.0 */ CURLE_ABORTED_BY_CALLBACK, /* 42 */ CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */ CURLE_OBSOLETE44, /* 44 - NOT USED */ @@ -556,6 +571,7 @@ typedef enum { /* compatibility with older names */ #define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING +#define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY /* The following were added in 7.21.5, April 2011 */ #define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION @@ -629,6 +645,7 @@ typedef enum { CONNECT HTTP/1.1 */ CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT HTTP/1.0 */ + CURLPROXY_HTTPS = 2, /* added in 7.52.0 */ CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already in 7.10 */ CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ @@ -1195,7 +1212,8 @@ typedef enum { CINIT(SHARE, OBJECTPOINT, 100), /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default), - CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */ + CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and + CURLPROXY_SOCKS5. */ CINIT(PROXYTYPE, LONG, 101), /* Set the Accept-Encoding string. Use this to tell a server you would like @@ -1689,6 +1707,77 @@ typedef enum { /* Set TCP Fast Open */ CINIT(TCP_FASTOPEN, LONG, 244), + /* Continue to send data if the server responds early with an + * HTTP status code >= 300 */ + CINIT(KEEP_SENDING_ON_ERROR, LONG, 245), + + /* The CApath or CAfile used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_CAINFO, STRINGPOINT, 246), + + /* The CApath directory used to validate the proxy certificate + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_CAPATH, STRINGPOINT, 247), + + /* Set if we should verify the proxy in ssl handshake, + set 1 to verify. */ + CINIT(PROXY_SSL_VERIFYPEER, LONG, 248), + + /* Set if we should verify the Common name from the proxy certificate in ssl + * handshake, set 1 to check existence, 2 to ensure that it matches + * the provided hostname. */ + CINIT(PROXY_SSL_VERIFYHOST, LONG, 249), + + /* What version to specifically try to use for proxy. + See CURL_SSLVERSION defines below. */ + CINIT(PROXY_SSLVERSION, LONG, 250), + + /* Set a username for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_USERNAME, STRINGPOINT, 251), + + /* Set a password for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_PASSWORD, STRINGPOINT, 252), + + /* Set authentication type for authenticated TLS for proxy */ + CINIT(PROXY_TLSAUTH_TYPE, STRINGPOINT, 253), + + /* name of the file keeping your private SSL-certificate for proxy */ + CINIT(PROXY_SSLCERT, STRINGPOINT, 254), + + /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for + proxy */ + CINIT(PROXY_SSLCERTTYPE, STRINGPOINT, 255), + + /* name of the file keeping your private SSL-key for proxy */ + CINIT(PROXY_SSLKEY, STRINGPOINT, 256), + + /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for + proxy */ + CINIT(PROXY_SSLKEYTYPE, STRINGPOINT, 257), + + /* password for the SSL private key for proxy */ + CINIT(PROXY_KEYPASSWD, STRINGPOINT, 258), + + /* Specify which SSL ciphers to use for proxy */ + CINIT(PROXY_SSL_CIPHER_LIST, STRINGPOINT, 259), + + /* CRL file for proxy */ + CINIT(PROXY_CRLFILE, STRINGPOINT, 260), + + /* Enable/disable specific SSL features with a bitmask for proxy, see + CURLSSLOPT_* */ + CINIT(PROXY_SSL_OPTIONS, LONG, 261), + + /* Name of pre proxy to use. */ + CINIT(PRE_PROXY, STRINGPOINT, 262), + + /* The public key in DER form used to validate the proxy public key + this option is used only if PROXY_SSL_VERIFYPEER is true */ + CINIT(PROXY_PINNEDPUBLICKEY, STRINGPOINT, 263), + + /* Path to an abstract Unix domain socket */ + CINIT(ABSTRACT_UNIX_SOCKET, STRINGPOINT, 264), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -1790,6 +1879,7 @@ enum { CURL_SSLVERSION_TLSv1_0, CURL_SSLVERSION_TLSv1_1, CURL_SSLVERSION_TLSv1_2, + CURL_SSLVERSION_TLSv1_3, CURL_SSLVERSION_LAST /* never use, keep last */ }; @@ -1824,7 +1914,10 @@ typedef enum { /* curl_strequal() and curl_strnequal() are subject for removal in a future - libcurl, see lib/README.curlx for details */ + libcurl, see lib/README.curlx for details + + !checksrc! disable SPACEBEFOREPAREN 2 +*/ CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2); CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n); @@ -2193,9 +2286,13 @@ typedef enum { CURLINFO_TLS_SESSION = CURLINFO_SLIST + 43, CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44, CURLINFO_TLS_SSL_PTR = CURLINFO_SLIST + 45, + CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46, + CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47, + CURLINFO_PROTOCOL = CURLINFO_LONG + 48, + CURLINFO_SCHEME = CURLINFO_STRING + 49, /* Fill in new entries below here! */ - CURLINFO_LASTONE = 45 + CURLINFO_LASTONE = 49 } CURLINFO; /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as @@ -2257,7 +2354,6 @@ typedef void (*curl_unlock_function)(CURL *handle, curl_lock_data data, void *userptr); -typedef void CURLSH; typedef enum { CURLSHE_OK, /* all is fine */ @@ -2357,6 +2453,7 @@ typedef struct { #define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */ #define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used for cookie domain verification */ +#define CURL_VERSION_HTTPS_PROXY (1<<21) /* HTTPS-proxy support built-in */ /* * NAME curl_version_info() diff --git a/contrib/curl/include/curl/curlver.h b/contrib/curl/include/curl/curlver.h index 7cea993e..349e9fe8 100644 --- a/contrib/curl/include/curl/curlver.h +++ b/contrib/curl/include/curl/curlver.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,16 +26,16 @@ a script at release-time. This was made its own header file in 7.11.2 */ /* This is the global package copyright */ -#define LIBCURL_COPYRIGHT "1996 - 2016 Daniel Stenberg, ." +#define LIBCURL_COPYRIGHT "1996 - 2017 Daniel Stenberg, ." /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "7.49.1-DEV" +#define LIBCURL_VERSION "7.53.1-DEV" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 49 +#define LIBCURL_VERSION_MINOR 53 #define LIBCURL_VERSION_PATCH 1 /* This is the numeric version of the libcurl version number, meant for easier @@ -57,7 +57,7 @@ CURL_VERSION_BITS() macro since curl's own configure script greps for it and needs it to contain the full number. */ -#define LIBCURL_VERSION_NUM 0x073101 +#define LIBCURL_VERSION_NUM 0x073501 /* * This is the date and time when the full source package was created. The diff --git a/contrib/curl/include/curl/easy.h b/contrib/curl/include/curl/easy.h index afc766cd..752c5049 100644 --- a/contrib/curl/include/curl/easy.h +++ b/contrib/curl/include/curl/easy.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2008, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -58,7 +58,7 @@ CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); * curl_easy_duphandle() for each new thread to avoid a series of identical * curl_easy_setopt() invokes in every thread. */ -CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl); +CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl); /* * NAME curl_easy_reset() diff --git a/contrib/curl/include/curl/multi.h b/contrib/curl/include/curl/multi.h index 0fbbd96f..d1e00cc5 100644 --- a/contrib/curl/include/curl/multi.h +++ b/contrib/curl/include/curl/multi.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -52,7 +52,11 @@ extern "C" { #endif +#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER) +typedef struct Curl_multi CURLM; +#else typedef void CURLM; +#endif typedef enum { CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or diff --git a/contrib/curl/include/curl/stdcheaders.h b/contrib/curl/include/curl/stdcheaders.h index 6f0f7f34..027b6f42 100644 --- a/contrib/curl/include/curl/stdcheaders.h +++ b/contrib/curl/include/curl/stdcheaders.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,8 +24,8 @@ #include -size_t fread (void *, size_t, size_t, FILE *); -size_t fwrite (const void *, size_t, size_t, FILE *); +size_t fread(void *, size_t, size_t, FILE *); +size_t fwrite(const void *, size_t, size_t, FILE *); int strcasecmp(const char *, const char *); int strncasecmp(const char *, const char *, size_t); diff --git a/contrib/curl/include/curl/typecheck-gcc.h b/contrib/curl/include/curl/typecheck-gcc.h index 6ec8bcfd..3d683152 100644 --- a/contrib/curl/include/curl/typecheck-gcc.h +++ b/contrib/curl/include/curl/typecheck-gcc.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -40,7 +40,7 @@ */ #define curl_easy_setopt(handle, option, value) \ __extension__ ({ \ - __typeof__ (option) _curl_opt = option; \ + __typeof__(option) _curl_opt = option; \ if(__builtin_constant_p(_curl_opt)) { \ if(_curl_is_long_option(_curl_opt)) \ if(!_curl_is_long(value)) \ @@ -110,7 +110,7 @@ __extension__ ({ \ /* FIXME: don't allow const pointers */ #define curl_easy_getinfo(handle, info, arg) \ __extension__ ({ \ - __typeof__ (info) _curl_info = info; \ + __typeof__(info) _curl_info = info; \ if(__builtin_constant_p(_curl_info)) { \ if(_curl_is_string_info(_curl_info)) \ if(!_curl_is_arr((arg), char *)) \ @@ -151,7 +151,7 @@ _CURL_WARNING(_curl_easy_setopt_err_curl_off_t, "curl_easy_setopt expects a curl_off_t argument for this option") _CURL_WARNING(_curl_easy_setopt_err_string, "curl_easy_setopt expects a " - "string (char* or char[]) argument for this option" + "string ('char *' or char[]) argument for this option" ) _CURL_WARNING(_curl_easy_setopt_err_write_callback, "curl_easy_setopt expects a curl_write_callback argument for this option") @@ -182,24 +182,25 @@ _CURL_WARNING(_curl_easy_setopt_err_error_buffer, "curl_easy_setopt expects a " "char buffer of CURL_ERROR_SIZE as argument for this option") _CURL_WARNING(_curl_easy_setopt_err_FILE, - "curl_easy_setopt expects a FILE* argument for this option") + "curl_easy_setopt expects a 'FILE *' argument for this option") _CURL_WARNING(_curl_easy_setopt_err_postfields, - "curl_easy_setopt expects a void* or char* argument for this option") + "curl_easy_setopt expects a 'void *' or 'char *' argument for this option") _CURL_WARNING(_curl_easy_setopt_err_curl_httpost, - "curl_easy_setopt expects a struct curl_httppost* argument for this option") + "curl_easy_setopt expects a 'struct curl_httppost *' " + "argument for this option") _CURL_WARNING(_curl_easy_setopt_err_curl_slist, - "curl_easy_setopt expects a struct curl_slist* argument for this option") + "curl_easy_setopt expects a 'struct curl_slist *' argument for this option") _CURL_WARNING(_curl_easy_setopt_err_CURLSH, "curl_easy_setopt expects a CURLSH* argument for this option") _CURL_WARNING(_curl_easy_getinfo_err_string, - "curl_easy_getinfo expects a pointer to char * for this info") + "curl_easy_getinfo expects a pointer to 'char *' for this info") _CURL_WARNING(_curl_easy_getinfo_err_long, "curl_easy_getinfo expects a pointer to long for this info") _CURL_WARNING(_curl_easy_getinfo_err_double, "curl_easy_getinfo expects a pointer to double for this info") _CURL_WARNING(_curl_easy_getinfo_err_curl_slist, - "curl_easy_getinfo expects a pointer to struct curl_slist * for this info") + "curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info") /* groups of curl_easy_setops options that take the same type of argument */ @@ -218,7 +219,8 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist, /* evaluates to true if option takes a char* argument */ #define _curl_is_string_option(option) \ - ((option) == CURLOPT_ACCEPT_ENCODING || \ + ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \ + (option) == CURLOPT_ACCEPT_ENCODING || \ (option) == CURLOPT_CAINFO || \ (option) == CURLOPT_CAPATH || \ (option) == CURLOPT_COOKIE || \ @@ -363,7 +365,7 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist, /* XXX: should evaluate to true iff expr is a pointer */ #define _curl_is_any_ptr(expr) \ - (sizeof(expr) == sizeof(void*)) + (sizeof(expr) == sizeof(void *)) /* evaluates to true if expr is NULL */ /* XXX: must not evaluate expr, so this check is not accurate */ @@ -455,12 +457,12 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist, _curl_callback_compatible((expr), _curl_read_callback4) || \ _curl_callback_compatible((expr), _curl_read_callback5) || \ _curl_callback_compatible((expr), _curl_read_callback6)) -typedef size_t (_curl_read_callback1)(char *, size_t, size_t, void*); -typedef size_t (_curl_read_callback2)(char *, size_t, size_t, const void*); -typedef size_t (_curl_read_callback3)(char *, size_t, size_t, FILE*); -typedef size_t (_curl_read_callback4)(void *, size_t, size_t, void*); -typedef size_t (_curl_read_callback5)(void *, size_t, size_t, const void*); -typedef size_t (_curl_read_callback6)(void *, size_t, size_t, FILE*); +typedef size_t (_curl_read_callback1)(char *, size_t, size_t, void *); +typedef size_t (_curl_read_callback2)(char *, size_t, size_t, const void *); +typedef size_t (_curl_read_callback3)(char *, size_t, size_t, FILE *); +typedef size_t (_curl_read_callback4)(void *, size_t, size_t, void *); +typedef size_t (_curl_read_callback5)(void *, size_t, size_t, const void *); +typedef size_t (_curl_read_callback6)(void *, size_t, size_t, FILE *); /* evaluates to true if expr is of type curl_write_callback or "similar" */ #define _curl_is_write_cb(expr) \ @@ -473,14 +475,14 @@ typedef size_t (_curl_read_callback6)(void *, size_t, size_t, FILE*); _curl_callback_compatible((expr), _curl_write_callback4) || \ _curl_callback_compatible((expr), _curl_write_callback5) || \ _curl_callback_compatible((expr), _curl_write_callback6)) -typedef size_t (_curl_write_callback1)(const char *, size_t, size_t, void*); +typedef size_t (_curl_write_callback1)(const char *, size_t, size_t, void *); typedef size_t (_curl_write_callback2)(const char *, size_t, size_t, - const void*); -typedef size_t (_curl_write_callback3)(const char *, size_t, size_t, FILE*); -typedef size_t (_curl_write_callback4)(const void *, size_t, size_t, void*); + const void *); +typedef size_t (_curl_write_callback3)(const char *, size_t, size_t, FILE *); +typedef size_t (_curl_write_callback4)(const void *, size_t, size_t, void *); typedef size_t (_curl_write_callback5)(const void *, size_t, size_t, - const void*); -typedef size_t (_curl_write_callback6)(const void *, size_t, size_t, FILE*); + const void *); +typedef size_t (_curl_write_callback6)(const void *, size_t, size_t, FILE *); /* evaluates to true if expr is of type curl_ioctl_callback or "similar" */ #define _curl_is_ioctl_cb(expr) \ @@ -490,10 +492,10 @@ typedef size_t (_curl_write_callback6)(const void *, size_t, size_t, FILE*); _curl_callback_compatible((expr), _curl_ioctl_callback2) || \ _curl_callback_compatible((expr), _curl_ioctl_callback3) || \ _curl_callback_compatible((expr), _curl_ioctl_callback4)) -typedef curlioerr (_curl_ioctl_callback1)(CURL *, int, void*); -typedef curlioerr (_curl_ioctl_callback2)(CURL *, int, const void*); -typedef curlioerr (_curl_ioctl_callback3)(CURL *, curliocmd, void*); -typedef curlioerr (_curl_ioctl_callback4)(CURL *, curliocmd, const void*); +typedef curlioerr (_curl_ioctl_callback1)(CURL *, int, void *); +typedef curlioerr (_curl_ioctl_callback2)(CURL *, int, const void *); +typedef curlioerr (_curl_ioctl_callback3)(CURL *, curliocmd, void *); +typedef curlioerr (_curl_ioctl_callback4)(CURL *, curliocmd, const void *); /* evaluates to true if expr is of type curl_sockopt_callback or "similar" */ #define _curl_is_sockopt_cb(expr) \ diff --git a/contrib/curl/lib/.gitignore b/contrib/curl/lib/.gitignore index b23f265d..719fc977 100644 --- a/contrib/curl/lib/.gitignore +++ b/contrib/curl/lib/.gitignore @@ -4,7 +4,6 @@ *.orig *.rej *.res -Makefile.vc*.dist TAGS curl_config.h curl_config.h.in diff --git a/contrib/curl/lib/CMakeLists.txt b/contrib/curl/lib/CMakeLists.txt index 49a34093..eb2de6d8 100644 --- a/contrib/curl/lib/CMakeLists.txt +++ b/contrib/curl/lib/CMakeLists.txt @@ -87,6 +87,11 @@ endif() set_target_properties(${LIB_NAME} PROPERTIES COMPILE_DEFINITIONS BUILDING_LIBCURL) +if(HIDES_CURL_PRIVATE_SYMBOLS) + set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS") + set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_FLAGS ${CURL_CFLAG_SYMBOLS_HIDE}) +endif() + # Remove the "lib" prefix since the library is already named "libcurl". set_target_properties(${LIB_NAME} PROPERTIES PREFIX "") set_target_properties(${LIB_NAME} PROPERTIES IMPORT_PREFIX "") diff --git a/contrib/curl/lib/Makefile.am b/contrib/curl/lib/Makefile.am index 12aaf614..cc7ee903 100644 --- a/contrib/curl/lib/Makefile.am +++ b/contrib/curl/lib/Makefile.am @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. +# Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -23,7 +23,7 @@ AUTOMAKE_OPTIONS = foreign nostdinc CMAKE_DIST = CMakeLists.txt curl_config.h.cmake -EXTRA_DIST = Makefile.b32 Makefile.m32 Makefile.vc6 config-win32.h \ +EXTRA_DIST = Makefile.b32 Makefile.m32 config-win32.h \ config-win32ce.h config-riscos.h config-mac.h curl_config.h.in \ makefile.dj config-dos.h libcurl.plist libcurl.rc config-amigaos.h \ makefile.amiga Makefile.netware nwlib.c nwos.c config-win32ce.h \ diff --git a/contrib/curl/lib/Makefile.inc b/contrib/curl/lib/Makefile.inc index 0ed998c1..19f58000 100644 --- a/contrib/curl/lib/Makefile.inc +++ b/contrib/curl/lib/Makefile.inc @@ -40,31 +40,31 @@ LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \ LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \ ldap.c version.c getenv.c escape.c mprintf.c telnet.c netrc.c \ - getinfo.c transfer.c strequal.c easy.c security.c curl_fnmatch.c \ + getinfo.c transfer.c strcase.c easy.c security.c curl_fnmatch.c \ fileinfo.c ftplistparser.c wildcard.c krb5.c memdebug.c http_chunks.c \ strtok.c connect.c llist.c hash.c multi.c content_encoding.c share.c \ http_digest.c md4.c md5.c http_negotiate.c inet_pton.c strtoofft.c \ strerror.c amigaos.c hostasyn.c hostip4.c hostip6.c hostsyn.c \ inet_ntop.c parsedate.c select.c tftp.c splay.c strdup.c socks.c \ - ssh.c rawstr.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \ + ssh.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \ curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c \ pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c \ openldap.c curl_gethostname.c gopher.c idn_win32.c \ http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.c \ - http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c \ + http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c rand.c \ curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c \ x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \ speedcheck.h urldata.h curl_ldap.h escape.h telnet.h getinfo.h \ - strequal.h curl_sec.h memdebug.h http_chunks.h curl_fnmatch.h \ + strcase.h curl_sec.h memdebug.h http_chunks.h curl_fnmatch.h \ wildcard.h fileinfo.h ftplistparser.h strtok.h connect.h llist.h \ hash.h content_encoding.h share.h curl_md4.h curl_md5.h http_digest.h \ http_negotiate.h inet_pton.h amigaos.h strtoofft.h strerror.h \ inet_ntop.h curlx.h curl_memory.h curl_setup.h transfer.h select.h \ easyif.h multiif.h parsedate.h tftp.h sockaddr.h splay.h strdup.h \ - socks.h ssh.h curl_base64.h rawstr.h curl_addrinfo.h curl_sspi.h \ + socks.h ssh.h curl_base64.h curl_addrinfo.h curl_sspi.h \ slist.h nonblock.h curl_memrchr.h imap.h pop3.h smtp.h pingpong.h \ rtsp.h curl_threads.h warnless.h curl_hmac.h curl_rtmp.h \ curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h \ @@ -72,7 +72,7 @@ LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \ curl_sasl.h curl_multibyte.h hostcheck.h conncache.h \ curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h \ x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \ - curl_printf.h system_win32.h + curl_printf.h system_win32.h rand.h LIB_RCFILES = libcurl.rc diff --git a/contrib/curl/lib/Makefile.m32 b/contrib/curl/lib/Makefile.m32 index 2142bfc4..522dbd1d 100644 --- a/contrib/curl/lib/Makefile.m32 +++ b/contrib/curl/lib/Makefile.m32 @@ -258,6 +258,10 @@ ifdef SSL CFLAGS += -DHAVE_OPENSSL_SRP -DUSE_TLS_SRP endif endif +else +ifdef WINSSL + DLL_LIBS += -lcrypt32 +endif endif ifdef ZLIB INCLUDES += -I"$(ZLIB_PATH)" diff --git a/contrib/curl/lib/Makefile.netware b/contrib/curl/lib/Makefile.netware index ee7e87ce..f689a36f 100644 --- a/contrib/curl/lib/Makefile.netware +++ b/contrib/curl/lib/Makefile.netware @@ -87,7 +87,7 @@ endif TARGET = libcurl VERSION = $(LIBCURL_VERSION) COPYR = Copyright (C) $(LIBCURL_COPYRIGHT_STR) -DESCR = cURL libcurl $(LIBCURL_VERSION_STR) ($(LIBARCH)) - https://curl.haxx.se +DESCR = curl libcurl $(LIBCURL_VERSION_STR) ($(LIBARCH)) - https://curl.haxx.se MTSAFE = YES STACK = 64000 SCREEN = none diff --git a/contrib/curl/lib/Makefile.vc6 b/contrib/curl/lib/Makefile.vc6 deleted file mode 100644 index 11f69c20..00000000 --- a/contrib/curl/lib/Makefile.vc6 +++ /dev/null @@ -1,689 +0,0 @@ -#*************************************************************************** -# _ _ ____ _ -# Project ___| | | | _ \| | -# / __| | | | |_) | | -# | (__| |_| | _ <| |___ -# \___|\___/|_| \_\_____| -# -# Copyright (C) 1999 - 2016, Daniel Stenberg, , et al. -# -# This software is licensed as described in the file COPYING, which -# you should have received as part of this distribution. The terms -# are also available at https://curl.haxx.se/docs/copyright.html. -# -# You may opt to use, copy, modify, merge, publish, distribute and/or sell -# copies of the Software, and permit persons to whom the Software is -# furnished to do so, under the terms of the COPYING file. -# -# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY -# KIND, either express or implied. -# -#*************************************************************************** - -# All files in the Makefile.vc* series are generated automatically from the -# one made for MSVC version 6. Alas, if you want to do changes to any of the -# files and send back to the project, edit the version six, make your diff and -# mail curl-library. - -########################################################################### -# -# Makefile for building libcurl with MSVC6 -# -# Usage: see usage message below -# Should be invoked from \lib directory -# Edit the paths and desired library name -# SSL path is only required if you intend compiling -# with SSL. -# -# This make file leaves the result either a .lib or .dll file -# in the \lib directory. It should be called from the \lib -# directory. -# -# An option would have been to allow the source directory to -# be specified, but I saw no requirement. -# -# Another option would have been to leave the .lib and .dll -# files in the "cfg" directory, but then the make file -# in \src would need to be changed. -# -############################################################## - -# ---------------------------------------------- -# Verify that current subdir is libcurl's 'lib' -# ---------------------------------------------- - -!IF ! EXIST(.\curl_addrinfo.c) -! MESSAGE Can not process this makefile from outside of libcurl's 'lib' subdirectory. -! MESSAGE Change to libcurl's 'lib' subdirectory, and try again. -! ERROR See previous message. -!ENDIF - -# ------------------------------------------------ -# Makefile.msvc.names provides libcurl file names -# ------------------------------------------------ - -!INCLUDE ..\winbuild\Makefile.msvc.names - -!IFNDEF OPENSSL_PATH -OPENSSL_PATH = ../../openssl-1.0.2a -!ENDIF - -!IFNDEF LIBSSH2_PATH -LIBSSH2_PATH = ../../libssh2-1.5.0 -!ENDIF - -!IFNDEF ZLIB_PATH -ZLIB_PATH = ../../zlib-1.2.8 -!ENDIF - -!IFNDEF MACHINE -MACHINE = X86 -!ENDIF - -# USE_WINDOWS_SSPI uses windows libraries to allow NTLM authentication -# without an openssl installation and offers the ability to authenticate -# using the "current logged in user". Since at least with MSVC6 the sspi.h -# header is broken it is either required to install the Windows SDK, -# or to fix sspi.h with adding this define at the beginning of sspi.h: -# #define FreeCredentialHandle FreeCredentialsHandle -# -# If, for some reason the Windows SDK is installed but not installed -# in the default location, you can specify WINDOWS_SDK_PATH. -# It can be downloaded from: -# https://msdn.microsoft.com/windows/bb980924.aspx - -# WINDOWS_SSPI = 1 - -!IFDEF WINDOWS_SSPI -!IFNDEF WINDOWS_SDK_PATH -WINDOWS_SDK_PATH = "$(PROGRAMFILES)\Microsoft SDK" -!ENDIF -!ENDIF - -############################################################# -## Nothing more to do below this line! - -CCNODBG = cl.exe /O2 /DNDEBUG -CCDEBUG = cl.exe /Od /Gm /Zi /D_DEBUG /GZ -CFLAGSSSL = /DUSE_OPENSSL /I "$(OPENSSL_PATH)/inc32" /I "$(OPENSSL_PATH)/inc32/openssl" -CFLAGSWINSSL = /DUSE_SCHANNEL -CFLAGSSSH2 = /DUSE_LIBSSH2 /DCURL_DISABLE_LDAP /DHAVE_LIBSSH2 /DHAVE_LIBSSH2_H /DLIBSSH2_WIN32 /DLIBSSH2_LIBRARY /I "$(LIBSSH2_PATH)/include" -CFLAGSZLIB = /DHAVE_ZLIB_H /DHAVE_ZLIB /DHAVE_LIBZ /I "$(ZLIB_PATH)" -CFLAGS = /I. /I../include /nologo /W3 /GX /DWIN32 /YX /FD /c /DBUILDING_LIBCURL /D_BIND_TO_CURRENT_VCLIBS_VERSION=1 -CFLAGSLIB = /DCURL_STATICLIB -LNKDLL = link.exe /DLL -LNKLIB = link.exe /lib -LFLAGS = /nologo /machine:$(MACHINE) -SSLLIBS = libeay32.lib ssleay32.lib -ZLIBLIBSDLL = zdll.lib -ZLIBLIBS = zlib.lib -WINLIBS = ws2_32.lib wldap32.lib advapi32.lib -CFLAGS = $(CFLAGS) - -CFGSET = FALSE - -!IFDEF WINDOWS_SSPI -CFLAGS = $(CFLAGS) /DUSE_WINDOWS_SSPI /I$(WINDOWS_SDK_PATH)\include -!ENDIF - -!IFDEF USE_IPV6 -CFLAGS = $(CFLAGS) /DUSE_IPV6 -!ENDIF - -!IFDEF USE_IDN -CFLAGS = $(CFLAGS) /DUSE_WIN32_IDN /DWANT_IDN_PROTOTYPES -!ENDIF - -############################################################## -# Runtime library configuration - -RTLIB = /MD -RTLIBD = /MDd - -!IF "$(RTLIBCFG)" == "static" -RTLIB = /MT -RTLIBD = /MTd -!ENDIF - - -###################### -# release - -!IF "$(CFG)" == "release" -TARGET = $(LIBCURL_STA_LIB_REL) -DIROBJ = $(CFG) -LNK = $(LNKLIB) /out:$(DIROBJ)\$(TARGET) -CC = $(CCNODBG) $(RTLIB) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# release-ssl - -!IF "$(CFG)" == "release-ssl" -TARGET = $(LIBCURL_STA_LIB_REL) -DIROBJ = $(CFG) -LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32" -LNK = $(LNKLIB) $(LFLAGSSSL) /out:$(DIROBJ)\$(TARGET) -CC = $(CCNODBG) $(RTLIB) $(CFLAGSSSL) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# release-winssl - -!IF "$(CFG)" == "release-winssl" -TARGET = $(LIBCURL_STA_LIB_REL) -DIROBJ = $(CFG) -LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" -LNK = $(LNKLIB) /out:$(DIROBJ)\$(TARGET) -CC = $(CCNODBG) $(RTLIB) $(CFLAGSWINSSL) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# release-zlib - -!IF "$(CFG)" == "release-zlib" -TARGET = $(LIBCURL_STA_LIB_REL) -DIROBJ = $(CFG) -LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" -LNK = $(LNKLIB) $(ZLIBLIBS) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET) -CC = $(CCNODBG) $(RTLIB) $(CFLAGSZLIB) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# release-ssl-zlib - -!IF "$(CFG)" == "release-ssl-zlib" -TARGET = $(LIBCURL_STA_LIB_REL) -DIROBJ = $(CFG) -LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32" -LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" -LNK = $(LNKLIB) $(LFLAGSSSL) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET) -CC = $(CCNODBG) $(RTLIB) $(CFLAGSSSL) $(CFLAGSZLIB) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# release-winssl-zlib - -!IF "$(CFG)" == "release-winssl-zlib" -TARGET = $(LIBCURL_STA_LIB_REL) -DIROBJ = $(CFG) -LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" -LNK = $(LNKLIB) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET) -CC = $(CCNODBG) $(RTLIB) $(CFLAGSWINSSL) $(CFLAGSZLIB) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# release-ssl-ssh2-zlib - -!IF "$(CFG)" == "release-ssl-ssh2-zlib" -TARGET = $(LIBCURL_STA_LIB_REL) -DIROBJ = $(CFG) -LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32" -LFLAGSSSH2 = "/LIBPATH:$(LIBSSH2_PATH)" -LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" -LNK = $(LNKLIB) $(LFLAGSSSL) $(LFLAGSSSH2) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET) -CC = $(CCNODBG) $(RTLIB) $(CFLAGSSSL) $(CFLAGSSSH2) $(CFLAGSZLIB) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# release-ssl-dll - -!IF "$(CFG)" == "release-ssl-dll" -TARGET = $(LIBCURL_STA_LIB_REL) -DIROBJ = $(CFG) -LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32dll" -LNK = $(LNKLIB) $(WINLIBS) $(SSLLIBS) $(LFLAGSSSL) /out:$(DIROBJ)\$(TARGET) -CC = $(CCNODBG) $(RTLIB) $(CFLAGSSSL) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# release-zlib-dll - -!IF "$(CFG)" == "release-zlib-dll" -TARGET = $(LIBCURL_STA_LIB_REL) -DIROBJ = $(CFG) -LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" -LNK = $(LNKLIB) $(WINLIBS) $(ZLIBLIBSDLL) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET) -CC = $(CCNODBG) $(RTLIB) $(CFLAGSZLIB) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# release-ssl-dll-zlib-dll - -!IF "$(CFG)" == "release-ssl-dll-zlib-dll" -TARGET = $(LIBCURL_STA_LIB_REL) -DIROBJ = $(CFG) -LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" -LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32dll" -LNK = $(LNKLIB) $(WINLIBS) $(SSLLIBS) $(ZLIBLIBSDLL) $(LFLAGSSSL) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET) -CC = $(CCNODBG) $(RTLIB) $(CFLAGSSSL) $(CFLAGSZLIB) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# release-dll - -!IF "$(CFG)" == "release-dll" -TARGET = $(LIBCURL_DYN_LIB_REL) -DIROBJ = $(CFG) -LNK = $(LNKDLL) $(WINLIBS) /out:$(DIROBJ)\$(TARGET) /IMPLIB:$(DIROBJ)\$(LIBCURL_IMP_LIB_REL) -CC = $(CCNODBG) $(RTLIB) -CFGSET = TRUE -RESOURCE = $(DIROBJ)\libcurl.res -!ENDIF - -###################### -# release-dll-ssl-dll - -!IF "$(CFG)" == "release-dll-ssl-dll" -TARGET = $(LIBCURL_DYN_LIB_REL) -DIROBJ = $(CFG) -LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32dll" -LNK = $(LNKDLL) $(WINLIBS) $(SSLLIBS) $(LFLAGSSSL) /out:$(DIROBJ)\$(TARGET) /IMPLIB:$(DIROBJ)\$(LIBCURL_IMP_LIB_REL) -CC = $(CCNODBG) $(RTLIB) $(CFLAGSSSL) -CFGSET = TRUE -RESOURCE = $(DIROBJ)\libcurl.res -!ENDIF - -###################### -# release-dll-zlib-dll - -!IF "$(CFG)" == "release-dll-zlib-dll" -TARGET = $(LIBCURL_DYN_LIB_REL) -DIROBJ = $(CFG) -LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" -LNK = $(LNKDLL) $(WINLIBS) $(ZLIBLIBSDLL) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET) /IMPLIB:$(DIROBJ)\$(LIBCURL_IMP_LIB_REL) -CC = $(CCNODBG) $(RTLIB) $(CFLAGSZLIB) -CFGSET = TRUE -RESOURCE = $(DIROBJ)\libcurl.res -!ENDIF - -###################### -# release-dll-ssl-dll-zlib-dll - -!IF "$(CFG)" == "release-dll-ssl-dll-zlib-dll" -TARGET = $(LIBCURL_DYN_LIB_REL) -DIROBJ = $(CFG) -LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" -LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32dll" -LNK = $(LNKDLL) $(WINLIBS) $(SSLLIBS) $(ZLIBLIBSDLL) $(LFLAGSSSL) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET) /IMPLIB:$(DIROBJ)\$(LIBCURL_IMP_LIB_REL) -CC = $(CCNODBG) $(RTLIB) $(CFLAGSSSL) $(CFLAGSZLIB) -CFGSET = TRUE -RESOURCE = $(DIROBJ)\libcurl.res -!ENDIF - -###################### -# debug - -!IF "$(CFG)" == "debug" -TARGET = $(LIBCURL_STA_LIB_DBG) -DIROBJ = $(CFG) -LNK = $(LNKLIB) /out:$(DIROBJ)\$(TARGET) -CC = $(CCDEBUG) $(RTLIBD) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# debug-ssl - -!IF "$(CFG)" == "debug-ssl" -TARGET = $(LIBCURL_STA_LIB_DBG) -DIROBJ = $(CFG) -LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32" -LNK = $(LNKLIB) $(LFLAGSSSL) /out:$(DIROBJ)\$(TARGET) -CC = $(CCDEBUG) $(RTLIBD) $(CFLAGSSSL) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# debug-zlib - -!IF "$(CFG)" == "debug-zlib" -TARGET = $(LIBCURL_STA_LIB_DBG) -DIROBJ = $(CFG) -LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" -LNK = $(LNKLIB) $(ZLIBLIBS) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET) -CC = $(CCDEBUG) $(RTLIBD) $(CFLAGSZLIB) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# debug-ssl-zlib - -!IF "$(CFG)" == "debug-ssl-zlib" -TARGET = $(LIBCURL_STA_LIB_DBG) -DIROBJ = $(CFG) -LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" -LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32" -LNK = $(LNKLIB) $(ZLIBLIBS) $(LFLAGSSSL) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET) -CC = $(CCDEBUG) $(RTLIBD) $(CFLAGSSSL) $(CFLAGSZLIB) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# debug-ssl-ssh2-zlib - -!IF "$(CFG)" == "debug-ssl-ssh2-zlib" -TARGET = $(LIBCURL_STA_LIB_DBG) -DIROBJ = $(CFG) -LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" -LFLAGSSSH2 = "/LIBPATH:$(LIBSSH2_PATH)" -LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32" -LNK = $(LNKLIB) $(ZLIBLIBS) $(LFLAGSSSL) $(LFLAGSSSH2) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET) -CC = $(CCDEBUG) $(RTLIBD) $(CFLAGSSSL) $(CFLAGSSSH2) $(CFLAGSZLIB) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# debug-ssl-dll - -!IF "$(CFG)" == "debug-ssl-dll" -TARGET = $(LIBCURL_STA_LIB_DBG) -DIROBJ = $(CFG) -LFLAGSSSL = /LIBPATH:$(OPENSSL_PATH)\out32dll -LNK = $(LNKLIB) $(WINLIBS) $(SSLLIBS) $(LFLAGSSSL) /out:$(DIROBJ)\$(TARGET) -CC = $(CCDEBUG) $(RTLIBD) $(CFLAGSSSL) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# debug-zlib-dll - -!IF "$(CFG)" == "debug-zlib-dll" -TARGET = $(LIBCURL_STA_LIB_DBG) -DIROBJ = $(CFG) -LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" -LNK = $(LNKLIB) $(WINLIBS) $(ZLIBLIBSDLL) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET) -CC = $(CCDEBUG) $(RTLIBD) $(CFLAGSZLIB) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# debug-ssl-dll-zlib-dll - -!IF "$(CFG)" == "debug-ssl-dll-zlib-dll" -TARGET = $(LIBCURL_STA_LIB_DBG) -DIROBJ = $(CFG) -LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" -LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32dll" -LNK = $(LNKLIB) $(WINLIBS) $(SSLLIBS) $(ZLIBLIBSDLL) $(LFLAGSSSL) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET) -CC = $(CCDEBUG) $(RTLIBD) $(CFLAGSSSL) $(CFLAGSZLIB) $(CFLAGSLIB) -CFGSET = TRUE -!ENDIF - -###################### -# debug-dll - -!IF "$(CFG)" == "debug-dll" -TARGET = $(LIBCURL_DYN_LIB_DBG) -DIROBJ = $(CFG) -LNK = $(LNKDLL) $(WINLIBS) /DEBUG /out:$(DIROBJ)\$(TARGET) /IMPLIB:$(DIROBJ)\$(LIBCURL_IMP_LIB_DBG) /PDB:$(DIROBJ)\$(LIBCURL_DYN_LIB_PDB) -CC = $(CCDEBUG) $(RTLIBD) -CFGSET = TRUE -RESOURCE = $(DIROBJ)\libcurl.res -!ENDIF - -###################### -# debug-dll-ssl-dll - -!IF "$(CFG)" == "debug-dll-ssl-dll" -TARGET = $(LIBCURL_DYN_LIB_DBG) -DIROBJ = $(CFG) -LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32dll" -LNK = $(LNKDLL) $(WINLIBS) $(SSLLIBS) $(LFLAGSSSL) /DEBUG /out:$(DIROBJ)\$(TARGET) /IMPLIB:$(DIROBJ)\$(LIBCURL_IMP_LIB_DBG) /PDB:$(DIROBJ)\$(LIBCURL_DYN_LIB_PDB) -CC = $(CCDEBUG) $(RTLIBD) $(CFLAGSSSL) -CFGSET = TRUE -RESOURCE = $(DIROBJ)\libcurl.res -!ENDIF - -###################### -# debug-dll-zlib-dll - -!IF "$(CFG)" == "debug-dll-zlib-dll" -TARGET = $(LIBCURL_DYN_LIB_DBG) -DIROBJ = $(CFG) -LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" -LNK = $(LNKDLL) $(WINLIBS) $(ZLIBLIBSDLL) $(LFLAGSZLIB) /DEBUG /out:$(DIROBJ)\$(TARGET) /IMPLIB:$(DIROBJ)\$(LIBCURL_IMP_LIB_DBG) /PDB:$(DIROBJ)\$(LIBCURL_DYN_LIB_PDB) -CC = $(CCDEBUG) $(RTLIBD) $(CFLAGSZLIB) -CFGSET = TRUE -RESOURCE = $(DIROBJ)\libcurl.res -!ENDIF - -###################### -# debug-dll-ssl-dll-zlib-dll - -!IF "$(CFG)" == "debug-dll-ssl-dll-zlib-dll" -TARGET = $(LIBCURL_DYN_LIB_DBG) -DIROBJ = $(CFG) -LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" -LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32dll" -LNK = $(LNKDLL) $(WINLIBS) $(SSLLIBS) $(ZLIBLIBSDLL) $(LFLAGSSSL) $(LFLAGSZLIB) /DEBUG /out:$(DIROBJ)\$(TARGET) /IMPLIB:$(DIROBJ)\$(LIBCURL_IMP_LIB_DBG) /PDB:$(DIROBJ)\$(LIBCURL_DYN_LIB_PDB) -CC = $(CCDEBUG) $(RTLIBD) $(CFLAGSSSL) $(CFLAGSZLIB) -CFGSET = TRUE -RESOURCE = $(DIROBJ)\libcurl.res -!ENDIF - -####################### -# Usage -# -!IF "$(CFGSET)" == "FALSE" && "$(CFG)" != "" -!MESSAGE Usage: nmake /f makefile.vc6 CFG= -!MESSAGE where is one of: -!MESSAGE release - release static library -!MESSAGE release-ssl - release static library with ssl -!MESSAGE release-zlib - release static library with zlib -!MESSAGE release-ssl-zlib - release static library with ssl and zlib -!MESSAGE release-ssl-ssh2-zlib - release static library with ssl, ssh2 and zlib -!MESSAGE release-ssl-dll - release static library with dynamic ssl -!MESSAGE release-zlib-dll - release static library with dynamic zlib -!MESSAGE release-ssl-dll-zlib-dll - release static library with dynamic ssl and dynamic zlib -!MESSAGE release-dll - release dynamic library -!MESSAGE release-dll-ssl-dll - release dynamic library with dynamic ssl -!MESSAGE release-dll-zlib-dll - release dynamic library with dynamic zlib -!MESSAGE release-dll-ssl-dll-zlib-dll - release dynamic library with dynamic ssl and dynamic zlib -!MESSAGE debug - debug static library -!MESSAGE debug-ssl - debug static library with ssl -!MESSAGE debug-zlib - debug static library with zlib -!MESSAGE debug-ssl-zlib - debug static library with ssl and zlib -!MESSAGE debug-ssl-ssh2-zlib - debug static library with ssl, ssh2 and zlib -!MESSAGE debug-ssl-dll - debug static library with dynamic ssl -!MESSAGE debug-zlib-dll - debug static library with dynamic zlib -!MESSAGE debug-ssl-dll-zlib-dll - debug static library with dynamic ssl and dynamic zlib -!MESSAGE debug-dll - debug dynamic library -!MESSAGE debug-dll-ssl-dll - debug dynamic library with dynamic ssl -!MESSAGE debug-dll-zlib-dll - debug dynamic library with dynamic zlib1 -!MESSAGE debug-dll-ssl-dll-zlib-dll - debug dynamic library with dynamic ssl and dynamic zlib -!MESSAGE can be left blank in which case all is assumed -!ERROR please choose a valid configuration "$(CFG)" -!ENDIF - -####################### -# Only the clean target can be used if a config was not provided. -# -!IF "$(CFGSET)" == "FALSE" -clean: - @-erase /s *.dll 2> NUL - @-erase /s *.exp 2> NUL - @-erase /s *.idb 2> NUL - @-erase /s *.lib 2> NUL - @-erase /s *.obj 2> NUL - @-erase /s *.pch 2> NUL - @-erase /s *.pdb 2> NUL - @-erase /s *.res 2> NUL -!ELSE -# A config was provided, so the library can be built. -# -X_OBJS= \ - $(DIROBJ)\amigaos.obj \ - $(DIROBJ)\asyn-ares.obj \ - $(DIROBJ)\asyn-thread.obj \ - $(DIROBJ)\axtls.obj \ - $(DIROBJ)\base64.obj \ - $(DIROBJ)\conncache.obj \ - $(DIROBJ)\connect.obj \ - $(DIROBJ)\content_encoding.obj \ - $(DIROBJ)\cookie.obj \ - $(DIROBJ)\curl_addrinfo.obj \ - $(DIROBJ)\curl_des.obj \ - $(DIROBJ)\curl_endian.obj \ - $(DIROBJ)\curl_fnmatch.obj \ - $(DIROBJ)\curl_gethostname.obj \ - $(DIROBJ)\curl_gssapi.obj \ - $(DIROBJ)\curl_memrchr.obj \ - $(DIROBJ)\curl_multibyte.obj \ - $(DIROBJ)\curl_ntlm_core.obj \ - $(DIROBJ)\curl_ntlm_wb.obj \ - $(DIROBJ)\curl_rtmp.obj \ - $(DIROBJ)\curl_sasl.obj \ - $(DIROBJ)\curl_sspi.obj \ - $(DIROBJ)\curl_threads.obj \ - $(DIROBJ)\cyassl.obj \ - $(DIROBJ)\darwinssl.obj \ - $(DIROBJ)\dict.obj \ - $(DIROBJ)\dotdot.obj \ - $(DIROBJ)\easy.obj \ - $(DIROBJ)\escape.obj \ - $(DIROBJ)\file.obj \ - $(DIROBJ)\fileinfo.obj \ - $(DIROBJ)\formdata.obj \ - $(DIROBJ)\ftp.obj \ - $(DIROBJ)\ftplistparser.obj \ - $(DIROBJ)\getenv.obj \ - $(DIROBJ)\getinfo.obj \ - $(DIROBJ)\gopher.obj \ - $(DIROBJ)\gtls.obj \ - $(DIROBJ)\hash.obj \ - $(DIROBJ)\hmac.obj \ - $(DIROBJ)\hostasyn.obj \ - $(DIROBJ)\hostcheck.obj \ - $(DIROBJ)\hostip.obj \ - $(DIROBJ)\hostip4.obj \ - $(DIROBJ)\hostip6.obj \ - $(DIROBJ)\hostsyn.obj \ - $(DIROBJ)\http.obj \ - $(DIROBJ)\http_chunks.obj \ - $(DIROBJ)\http_digest.obj \ - $(DIROBJ)\http_negotiate.obj \ - $(DIROBJ)\http_ntlm.obj \ - $(DIROBJ)\http_proxy.obj \ - $(DIROBJ)\idn_win32.obj \ - $(DIROBJ)\if2ip.obj \ - $(DIROBJ)\imap.obj \ - $(DIROBJ)\inet_ntop.obj \ - $(DIROBJ)\inet_pton.obj \ - $(DIROBJ)\krb5.obj \ - $(DIROBJ)\ldap.obj \ - $(DIROBJ)\llist.obj \ - $(DIROBJ)\md4.obj \ - $(DIROBJ)\md5.obj \ - $(DIROBJ)\memdebug.obj \ - $(DIROBJ)\mprintf.obj \ - $(DIROBJ)\multi.obj \ - $(DIROBJ)\netrc.obj \ - $(DIROBJ)\non-ascii.obj \ - $(DIROBJ)\nonblock.obj \ - $(DIROBJ)\nss.obj \ - $(DIROBJ)\openldap.obj \ - $(DIROBJ)\parsedate.obj \ - $(DIROBJ)\pingpong.obj \ - $(DIROBJ)\pipeline.obj \ - $(DIROBJ)\polarssl.obj \ - $(DIROBJ)\polarssl_threadlock.obj \ - $(DIROBJ)\pop3.obj \ - $(DIROBJ)\progress.obj \ - $(DIROBJ)\rawstr.obj \ - $(DIROBJ)\rtsp.obj \ - $(DIROBJ)\schannel.obj \ - $(DIROBJ)\security.obj \ - $(DIROBJ)\select.obj \ - $(DIROBJ)\sendf.obj \ - $(DIROBJ)\share.obj \ - $(DIROBJ)\slist.obj \ - $(DIROBJ)\smb.obj \ - $(DIROBJ)\smtp.obj \ - $(DIROBJ)\socks.obj \ - $(DIROBJ)\socks_gssapi.obj \ - $(DIROBJ)\socks_sspi.obj \ - $(DIROBJ)\speedcheck.obj \ - $(DIROBJ)\splay.obj \ - $(DIROBJ)\ssh.obj \ - $(DIROBJ)\system_win32.obj \ - $(DIROBJ)\vauth.obj \ - $(DIROBJ)\cleartext.obj \ - $(DIROBJ)\cram.obj \ - $(DIROBJ)\digest.obj \ - $(DIROBJ)\digest_sspi.obj \ - $(DIROBJ)\krb5_gssapi.obj \ - $(DIROBJ)\krb5_sspi.obj \ - $(DIROBJ)\ntlm.obj \ - $(DIROBJ)\ntlm_sspi.obj \ - $(DIROBJ)\oauth2.obj \ - $(DIROBJ)\spnego_gssapi.obj \ - $(DIROBJ)\spnego_sspi.obj \ - $(DIROBJ)\vtls.obj \ - $(DIROBJ)\openssl.obj \ - $(DIROBJ)\strdup.obj \ - $(DIROBJ)\strequal.obj \ - $(DIROBJ)\strerror.obj \ - $(DIROBJ)\strtok.obj \ - $(DIROBJ)\strtoofft.obj \ - $(DIROBJ)\telnet.obj \ - $(DIROBJ)\tftp.obj \ - $(DIROBJ)\timeval.obj \ - $(DIROBJ)\transfer.obj \ - $(DIROBJ)\url.obj \ - $(DIROBJ)\version.obj \ - $(DIROBJ)\warnless.obj \ - $(DIROBJ)\wildcard.obj \ - $(RESOURCE) - -all : $(TARGET) - -$(TARGET): $(X_OBJS) - $(LNK) $(LFLAGS) $(X_OBJS) - -xcopy $(DIROBJ)\$(LIBCURL_STA_LIB_REL) . /y - -xcopy $(DIROBJ)\$(LIBCURL_STA_LIB_DBG) . /y - -xcopy $(DIROBJ)\$(LIBCURL_DYN_LIB_REL) . /y - -xcopy $(DIROBJ)\$(LIBCURL_DYN_LIB_DBG) . /y - -xcopy $(DIROBJ)\$(LIBCURL_IMP_LIB_REL) . /y - -xcopy $(DIROBJ)\$(LIBCURL_IMP_LIB_DBG) . /y - -xcopy $(DIROBJ)\*.exp . /y - -xcopy $(DIROBJ)\*.pdb . /y - -$(X_OBJS): $(DIROBJ) - -$(DIROBJ): - @if not exist "$(DIROBJ)" mkdir $(DIROBJ) - -.SUFFIXES: .c .obj .res - -{.\}.c{$(DIROBJ)\}.obj: - $(CC) $(CFLAGS) /Fo"$@" $< - -{.\vauth\}.c{$(DIROBJ)\}.obj: - $(CC) $(CFLAGS) /Fo"$@" $< - -{.\vtls\}.c{$(DIROBJ)\}.obj: - $(CC) $(CFLAGS) /Fo"$@" $< - -debug-dll\libcurl.res \ -debug-dll-ssl-dll\libcurl.res \ -debug-dll-zlib-dll\libcurl.res \ -debug-dll-ssl-dll-zlib-dll\libcurl.res: libcurl.rc - rc /dDEBUGBUILD=1 /Fo $@ libcurl.rc - -release-dll\libcurl.res \ -release-dll-ssl-dll\libcurl.res \ -release-dll-zlib-dll\libcurl.res \ -release-dll-ssl-dll-zlib-dll\libcurl.res: libcurl.rc - rc /dDEBUGBUILD=0 /Fo $@ libcurl.rc -!ENDIF # End of case where a config was provided. diff --git a/contrib/curl/lib/amigaos.c b/contrib/curl/lib/amigaos.c index 5591d222..4f55b30e 100644 --- a/contrib/curl/lib/amigaos.c +++ b/contrib/curl/lib/amigaos.c @@ -57,7 +57,7 @@ bool Curl_amiga_init() } if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno, - SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "cURL", + SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "curl", TAG_DONE)) { __request("SocketBaseTags ERROR"); return FALSE; diff --git a/contrib/curl/lib/asyn-ares.c b/contrib/curl/lib/asyn-ares.c index 51f61dee..c038c2a3 100644 --- a/contrib/curl/lib/asyn-ares.c +++ b/contrib/curl/lib/asyn-ares.c @@ -169,7 +169,7 @@ int Curl_resolver_duphandle(void **to, void *from) return CURLE_OK; } -static void destroy_async_data (struct Curl_async *async); +static void destroy_async_data(struct Curl_async *async); /* * Cancel all possibly still on-going resolves for this connection. @@ -184,7 +184,7 @@ void Curl_resolver_cancel(struct connectdata *conn) /* * destroy_async_data() cleans up async resolver data. */ -static void destroy_async_data (struct Curl_async *async) +static void destroy_async_data(struct Curl_async *async) { free(async->hostname); @@ -249,7 +249,7 @@ int Curl_resolver_getsock(struct connectdata *conn, static int waitperform(struct connectdata *conn, int timeout_ms) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int nfds; int bitmask; ares_socket_t socks[ARES_GETSOCK_MAXNUM]; @@ -309,7 +309,7 @@ static int waitperform(struct connectdata *conn, int timeout_ms) CURLcode Curl_resolver_is_resolved(struct connectdata *conn, struct Curl_dns_entry **dns) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ResolverResults *res = (struct ResolverResults *) conn->async.os_specific; CURLcode result = CURLE_OK; @@ -353,7 +353,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, struct Curl_dns_entry **entry) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; long timeout; struct timeval now = Curl_tvnow(); struct Curl_dns_entry *temp_entry; @@ -492,7 +492,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, int *waitp) { char *bufp; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct in_addr in; int family = PF_INET; #ifdef ENABLE_IPV6 /* CURLRES_IPV6 */ @@ -583,7 +583,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, return NULL; /* no struct yet */ } -CURLcode Curl_set_dns_servers(struct SessionHandle *data, +CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers) { CURLcode result = CURLE_NOT_BUILT_IN; @@ -621,7 +621,7 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data, return result; } -CURLcode Curl_set_dns_interface(struct SessionHandle *data, +CURLcode Curl_set_dns_interface(struct Curl_easy *data, const char *interf) { #if (ARES_VERSION >= 0x010704) @@ -638,7 +638,7 @@ CURLcode Curl_set_dns_interface(struct SessionHandle *data, #endif } -CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, +CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, const char *local_ip4) { #if (ARES_VERSION >= 0x010704) @@ -663,7 +663,7 @@ CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, #endif } -CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data, +CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, const char *local_ip6) { #if (ARES_VERSION >= 0x010704) && defined(ENABLE_IPV6) diff --git a/contrib/curl/lib/asyn-thread.c b/contrib/curl/lib/asyn-thread.c index 81caedb0..26a15b11 100644 --- a/contrib/curl/lib/asyn-thread.c +++ b/contrib/curl/lib/asyn-thread.c @@ -155,8 +155,8 @@ struct thread_sync_data { curl_mutex_t * mtx; int done; - char * hostname; /* hostname to resolve, Curl_async.hostname - duplicate */ + char *hostname; /* hostname to resolve, Curl_async.hostname + duplicate */ int port; int sock_error; Curl_addrinfo *res; @@ -169,7 +169,7 @@ struct thread_sync_data { struct thread_data { curl_thread_t thread_hnd; unsigned int poll_interval; - long interval_end; + time_t interval_end; struct thread_sync_data tsd; }; @@ -200,7 +200,7 @@ void destroy_thread_sync_data(struct thread_sync_data * tsd) /* Initialize resolver thread synchronization data */ static int init_thread_sync_data(struct thread_data * td, - const char * hostname, + const char *hostname, int port, const struct addrinfo *hints) { @@ -263,7 +263,7 @@ static int getaddrinfo_complete(struct connectdata *conn) * For builds without ARES, but with ENABLE_IPV6, create a resolver thread * and wait on it. */ -static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg) +static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg) { struct thread_sync_data *tsd = (struct thread_sync_data*)arg; struct thread_data *td = tsd->td; @@ -279,6 +279,9 @@ static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg) if(tsd->sock_error == 0) tsd->sock_error = RESOLVER_ENOMEM; } + else { + Curl_addrinfo_set_port(tsd->res, tsd->port); + } Curl_mutex_acquire(tsd->mtx); if(tsd->done) { @@ -300,7 +303,7 @@ static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg) /* * gethostbyname_thread() resolves a name and then exits. */ -static unsigned int CURL_STDCALL gethostbyname_thread (void *arg) +static unsigned int CURL_STDCALL gethostbyname_thread(void *arg) { struct thread_sync_data *tsd = (struct thread_sync_data *)arg; struct thread_data *td = tsd->td; @@ -333,7 +336,7 @@ static unsigned int CURL_STDCALL gethostbyname_thread (void *arg) /* * destroy_async_data() cleans up async resolver data and thread handle. */ -static void destroy_async_data (struct Curl_async *async) +static void destroy_async_data(struct Curl_async *async) { if(async->os_specific) { struct thread_data *td = (struct thread_data*) async->os_specific; @@ -372,14 +375,14 @@ static void destroy_async_data (struct Curl_async *async) * * Returns FALSE in case of failure, otherwise TRUE. */ -static bool init_resolve_thread (struct connectdata *conn, - const char *hostname, int port, - const struct addrinfo *hints) +static bool init_resolve_thread(struct connectdata *conn, + const char *hostname, int port, + const struct addrinfo *hints) { struct thread_data *td = calloc(1, sizeof(struct thread_data)); int err = RESOLVER_ENOMEM; - conn->async.os_specific = (void*) td; + conn->async.os_specific = (void *)td; if(!td) goto err_exit; @@ -494,7 +497,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, CURLcode Curl_resolver_is_resolved(struct connectdata *conn, struct Curl_dns_entry **entry) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct thread_data *td = (struct thread_data*) conn->async.os_specific; int done = 0; @@ -522,7 +525,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, } else { /* poll for name lookup done with exponential backoff up to 250ms */ - long elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); + time_t elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle); if(elapsed < 0) elapsed = 0; @@ -602,6 +605,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, *waitp = 0; /* default to synchronous response */ +#ifndef USE_RESOLVE_ON_IPS /* First check if this is an IPv4 address string */ if(Curl_inet_pton(AF_INET, hostname, &in) > 0) /* This is a dotted IP address 123.123.123.123-style */ @@ -609,10 +613,13 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, #ifdef CURLRES_IPV6 /* check if this is an IPv6 address string */ - if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0) + if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0) /* This is an IPv6 address literal */ return Curl_ip2addr(AF_INET6, &in6, hostname, port); +#endif /* CURLRES_IPV6 */ +#endif /* !USE_RESOLVE_ON_IPS */ +#ifdef CURLRES_IPV6 /* * Check if a limited name resolve has been requested. */ @@ -631,7 +638,6 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, if((pf != PF_INET) && !Curl_ipv6works()) /* The stack seems to be a non-IPv6 one */ pf = PF_INET; - #endif /* CURLRES_IPV6 */ memset(&hints, 0, sizeof(hints)); @@ -656,12 +662,16 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, hostname, port, Curl_strerror(conn, SOCKERRNO)); return NULL; } + else { + Curl_addrinfo_set_port(res, port); + } + return res; } #endif /* !HAVE_GETADDRINFO */ -CURLcode Curl_set_dns_servers(struct SessionHandle *data, +CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers) { (void)data; @@ -670,7 +680,7 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data, } -CURLcode Curl_set_dns_interface(struct SessionHandle *data, +CURLcode Curl_set_dns_interface(struct Curl_easy *data, const char *interf) { (void)data; @@ -678,7 +688,7 @@ CURLcode Curl_set_dns_interface(struct SessionHandle *data, return CURLE_NOT_BUILT_IN; } -CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, +CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, const char *local_ip4) { (void)data; @@ -686,7 +696,7 @@ CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, return CURLE_NOT_BUILT_IN; } -CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data, +CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, const char *local_ip6) { (void)data; diff --git a/contrib/curl/lib/asyn.h b/contrib/curl/lib/asyn.h index 416510f9..3adc3664 100644 --- a/contrib/curl/lib/asyn.h +++ b/contrib/curl/lib/asyn.h @@ -27,7 +27,7 @@ struct addrinfo; struct hostent; -struct SessionHandle; +struct Curl_easy; struct connectdata; struct Curl_dns_entry; diff --git a/contrib/curl/lib/base64.c b/contrib/curl/lib/base64.c index 0ef24d51..204a2273 100644 --- a/contrib/curl/lib/base64.c +++ b/contrib/curl/lib/base64.c @@ -23,7 +23,7 @@ /* Base64 encoding/decoding */ #include "curl_setup.h" -#include "urldata.h" /* for the SessionHandle definition */ +#include "urldata.h" /* for the Curl_easy definition */ #include "warnless.h" #include "curl_base64.h" #include "non-ascii.h" @@ -169,7 +169,7 @@ CURLcode Curl_base64_decode(const char *src, } static CURLcode base64_encode(const char *table64, - struct SessionHandle *data, + struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen) { @@ -190,6 +190,11 @@ static CURLcode base64_encode(const char *table64, if(!insize) insize = strlen(indata); +#if SIZEOF_SIZE_T == 4 + if(insize > UINT_MAX/4) + return CURLE_OUT_OF_MEMORY; +#endif + base64data = output = malloc(insize * 4 / 3 + 4); if(!output) return CURLE_OUT_OF_MEMORY; @@ -283,7 +288,7 @@ static CURLcode base64_encode(const char *table64, * * @unittest: 1302 */ -CURLcode Curl_base64_encode(struct SessionHandle *data, +CURLcode Curl_base64_encode(struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen) { @@ -307,7 +312,7 @@ CURLcode Curl_base64_encode(struct SessionHandle *data, * * @unittest: 1302 */ -CURLcode Curl_base64url_encode(struct SessionHandle *data, +CURLcode Curl_base64url_encode(struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen) { diff --git a/contrib/curl/lib/checksrc.pl b/contrib/curl/lib/checksrc.pl index aacb242b..7857bbfc 100644 --- a/contrib/curl/lib/checksrc.pl +++ b/contrib/curl/lib/checksrc.pl @@ -55,7 +55,10 @@ my %warnings = ( 'COPYRIGHT' => 'file missing a copyright statement', 'BADCOMMAND' => 'bad !checksrc! instruction', 'UNUSEDIGNORE' => 'a warning ignore was not used', - 'OPENCOMMENT' => 'file ended with a /* comment still "open"' + 'OPENCOMMENT' => 'file ended with a /* comment still "open"', + 'ASTERISKSPACE' => 'pointer declared with space after asterisk', + 'ASTERISKNOSPACE' => 'pointer declared without space before asterisk', + 'ASSIGNWITHINCONDITION' => 'assignment within conditional expression' ); sub readwhitelist { @@ -241,6 +244,12 @@ sub checksrc { } } +sub nostrings { + my ($str) = @_; + $str =~ s/\".*\"//g; + return $str; +} + sub scanfile { my ($file) = @_; @@ -327,17 +336,35 @@ sub scanfile { $line, length($1), $file, $l, "\/\/ comment"); } - # check spaces after for/if/while - if($l =~ /^(.*)(for|if|while) \(/) { + my $nostr = nostrings($l); + # check spaces after for/if/while/function call + if($nostr =~ /^(.*)(for|if|while| ([a-zA-Z0-9_]+)) \((.)/) { if($1 =~ / *\#/) { # this is a #if, treat it differently } + elsif($3 eq "return") { + # return must have a space + } + elsif($4 eq "*") { + # (* beginning makes the space OK! + } + elsif($1 =~ / *typedef/) { + # typedefs can use space-paren + } else { checkwarn("SPACEBEFOREPAREN", $line, length($1)+length($2), $file, $l, "$2 with space"); } } + if($nostr =~ /^((.*)(if) *\()(.*)\)/) { + my $pos = length($1); + if($4 =~ / = /) { + checkwarn("ASSIGNWITHINCONDITION", + $line, $pos+1, $file, $l, + "assignment within conditional expression"); + } + } # check spaces after open parentheses if($l =~ /^(.*[a-z])\( /i) { checkwarn("SPACEAFTERPAREN", @@ -421,7 +448,14 @@ sub scanfile { } # scan for use of banned functions - if($l =~ /^(.*\W)(sprintf|vsprintf|strcat|strncat|_mbscat|_mbsncat|_tcscat|_tcsncat|wcscat|wcsncat|gets)\s*\(/) { + if($l =~ /^(.*\W) + (gets| + strtok| + v?sprintf| + (str|_mbs|_tcs|_wcs)n?cat| + LoadLibrary(Ex)?(A|W)?) + \s*\( + /x) { checkwarn("BANNEDFUNC", $line, length($1), $file, $ol, "use of $2 is banned"); @@ -464,6 +498,31 @@ sub scanfile { } } + # check for 'char * name' + if(($l =~ /(^.*(char|int|long|void|curl_slist|CURL|CURLM|CURLMsg|curl_httppost) *(\*+)) (\w+)/) && ($4 ne "const")) { + checkwarn("ASTERISKNOSPACE", + $line, length($1), $file, $ol, + "no space after declarative asterisk"); + } + # check for 'char*' + if(($l =~ /(^.*(char|int|long|void|curl_slist|CURL|CURLM|CURLMsg|curl_httppost|sockaddr_in|FILE)\*)/)) { + checkwarn("ASTERISKNOSPACE", + $line, length($1)-1, $file, $ol, + "no space before asterisk"); + } + + # check for 'void func() {', but avoid false positives by requiring + # both an open and closed parentheses before the open brace + if($l =~ /^((\w).*){\z/) { + my $k = $1; + $k =~ s/const *//; + $k =~ s/static *//; + if($k =~ /\(.*\)/) { + checkwarn("BRACEPOS", + $line, length($l)-1, $file, $ol, + "wrongly placed open brace"); + } + } $line++; $prevl = $ol; } diff --git a/contrib/curl/lib/config-amigaos.h b/contrib/curl/lib/config-amigaos.h index 74f5f527..31cfc3af 100644 --- a/contrib/curl/lib/config-amigaos.h +++ b/contrib/curl/lib/config-amigaos.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -98,7 +98,7 @@ #define OS "AmigaOS" #define PACKAGE "curl" -#define PACKAGE_BUGREPORT "curl-bug@haxx.se" +#define PACKAGE_BUGREPORT "a suitable mailing list: https://curl.haxx.se/mail/" #define PACKAGE_NAME "curl" #define PACKAGE_STRING "curl -" #define PACKAGE_TARNAME "curl" diff --git a/contrib/curl/lib/config-symbian.h b/contrib/curl/lib/config-symbian.h index 2603a46b..92983d24 100644 --- a/contrib/curl/lib/config-symbian.h +++ b/contrib/curl/lib/config-symbian.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -676,7 +676,7 @@ /*#define RANDOM_FILE "/dev/urandom"*/ #define RECV_TYPE_ARG1 int -#define RECV_TYPE_ARG2 void* +#define RECV_TYPE_ARG2 void * #define RECV_TYPE_ARG3 size_t #define RECV_TYPE_ARG4 int #define RECV_TYPE_RETV ssize_t @@ -692,7 +692,7 @@ #define SEND_TYPE_ARG1 int #define SEND_QUAL_ARG2 const -#define SEND_TYPE_ARG2 void* +#define SEND_TYPE_ARG2 void * #define SEND_TYPE_ARG3 size_t #define SEND_TYPE_ARG4 int #define SEND_TYPE_RETV ssize_t diff --git a/contrib/curl/lib/conncache.c b/contrib/curl/lib/conncache.c index d0c09c82..a51c8fd7 100644 --- a/contrib/curl/lib/conncache.c +++ b/contrib/curl/lib/conncache.c @@ -30,7 +30,6 @@ #include "progress.h" #include "multiif.h" #include "sendf.h" -#include "rawstr.h" #include "conncache.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -45,7 +44,7 @@ static void conn_llist_dtor(void *user, void *element) data->bundle = NULL; } -static CURLcode bundle_create(struct SessionHandle *data, +static CURLcode bundle_create(struct Curl_easy *data, struct connectbundle **cb_ptr) { (void)data; @@ -133,14 +132,16 @@ static char *hashkey(struct connectdata *conn) { const char *hostname; - if(conn->bits.proxy) - hostname = conn->proxy.name; + if(conn->bits.socksproxy) + hostname = conn->socks_proxy.host.name; + else if(conn->bits.httpproxy) + hostname = conn->http_proxy.host.name; else if(conn->bits.conn_to_host) hostname = conn->conn_to_host.name; else hostname = conn->host.name; - return aprintf("%s:%d", hostname, conn->port); + return aprintf("%s:%ld", hostname, conn->port); } /* Look up the bundle with all the connections to the same host this @@ -199,7 +200,7 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc, CURLcode result; struct connectbundle *bundle; struct connectbundle *new_bundle = NULL; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache); if(!bundle) { diff --git a/contrib/curl/lib/connect.c b/contrib/curl/lib/connect.c index ac2f2683..524d885e 100644 --- a/contrib/curl/lib/connect.c +++ b/contrib/curl/lib/connect.c @@ -72,6 +72,7 @@ #include "warnless.h" #include "conncache.h" #include "multihandle.h" +#include "system_win32.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -103,7 +104,7 @@ struct tcp_keepalive { #endif static void -tcpkeepalive(struct SessionHandle *data, +tcpkeepalive(struct Curl_easy *data, curl_socket_t sockfd) { int optval = data->set.tcp_keepalive?1:0; @@ -178,12 +179,12 @@ singleipconnect(struct connectdata *conn, * * @unittest: 1303 */ -long Curl_timeleft(struct SessionHandle *data, - struct timeval *nowp, - bool duringconnect) +time_t Curl_timeleft(struct Curl_easy *data, + struct timeval *nowp, + bool duringconnect) { int timeout_set = 0; - long timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0; + time_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0; struct timeval now; /* if a timeout is set, use the most restrictive one */ @@ -193,7 +194,7 @@ long Curl_timeleft(struct SessionHandle *data, if(duringconnect && (data->set.connecttimeout > 0)) timeout_set |= 2; - switch (timeout_set) { + switch(timeout_set) { case 1: timeout_ms = data->set.timeout; break; @@ -238,7 +239,7 @@ long Curl_timeleft(struct SessionHandle *data, static CURLcode bindlocal(struct connectdata *conn, curl_socket_t sockfd, int af, unsigned int scope) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct Curl_sockaddr_storage sa; struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */ @@ -600,26 +601,28 @@ void Curl_persistconninfo(struct connectdata *conn) { memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN); memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN); + conn->data->info.conn_scheme = conn->handler->scheme; + conn->data->info.conn_protocol = conn->handler->protocol; conn->data->info.conn_primary_port = conn->primary_port; conn->data->info.conn_local_port = conn->local_port; } /* retrieves ip address and port from a sockaddr structure */ -static bool getaddressinfo(struct sockaddr* sa, char* addr, - long* port) +static bool getaddressinfo(struct sockaddr *sa, char *addr, + long *port) { unsigned short us_port; - struct sockaddr_in* si = NULL; + struct sockaddr_in *si = NULL; #ifdef ENABLE_IPV6 - struct sockaddr_in6* si6 = NULL; + struct sockaddr_in6 *si6 = NULL; #endif #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX) - struct sockaddr_un* su = NULL; + struct sockaddr_un *su = NULL; #endif - switch (sa->sa_family) { + switch(sa->sa_family) { case AF_INET: - si = (struct sockaddr_in*)(void*) sa; + si = (struct sockaddr_in *)(void *) sa; if(Curl_inet_ntop(sa->sa_family, &si->sin_addr, addr, MAX_IPADR_LEN)) { us_port = ntohs(si->sin_port); @@ -629,7 +632,7 @@ static bool getaddressinfo(struct sockaddr* sa, char* addr, break; #ifdef ENABLE_IPV6 case AF_INET6: - si6 = (struct sockaddr_in6*)(void*) sa; + si6 = (struct sockaddr_in6 *)(void *) sa; if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr, addr, MAX_IPADR_LEN)) { us_port = ntohs(si6->sin6_port); @@ -662,7 +665,7 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd) curl_socklen_t len; struct Curl_sockaddr_storage ssrem; struct Curl_sockaddr_storage ssloc; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(conn->socktype == SOCK_DGRAM) /* there's no connection! */ @@ -719,9 +722,9 @@ CURLcode Curl_is_connected(struct connectdata *conn, int sockindex, bool *connected) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result = CURLE_OK; - long allow; + time_t allow; int error = 0; struct timeval now; int rc; @@ -761,7 +764,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, #endif /* check socket for connect */ - rc = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0); + rc = SOCKET_WRITABLE(conn->tempsock[i], 0); if(rc == 0) { /* no connection yet */ error = 0; @@ -842,7 +845,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, if(result) { /* no more addresses to try */ - const char* hostname; + const char *hostname; /* if the first address family runs out of addresses to try before the happy eyeball timeout, go ahead and try the next family now */ @@ -852,8 +855,10 @@ CURLcode Curl_is_connected(struct connectdata *conn, return result; } - if(conn->bits.proxy) - hostname = conn->proxy.name; + if(conn->bits.socksproxy) + hostname = conn->socks_proxy.host.name; + else if(conn->bits.httpproxy) + hostname = conn->http_proxy.host.name; else if(conn->bits.conn_to_host) hostname = conn->conn_to_host.name; else @@ -870,7 +875,7 @@ void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd) { #if defined(TCP_NODELAY) #if !defined(CURL_DISABLE_VERBOSE_STRINGS) - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; #endif curl_socklen_t onoff = (curl_socklen_t) 1; int level = IPPROTO_TCP; @@ -912,7 +917,7 @@ void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd) static void nosigpipe(struct connectdata *conn, curl_socket_t sockfd) { - struct SessionHandle *data= conn->data; + struct Curl_easy *data= conn->data; int onoff = 1; if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff, sizeof(onoff)) < 0) @@ -945,43 +950,15 @@ void Curl_sndbufset(curl_socket_t sockfd) int val = CURL_MAX_WRITE_SIZE + 32; int curval = 0; int curlen = sizeof(curval); - DWORD majorVersion = 6; static int detectOsState = DETECT_OS_NONE; if(detectOsState == DETECT_OS_NONE) { -#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ - (_WIN32_WINNT < _WIN32_WINNT_WIN2K) - OSVERSIONINFO osver; - - memset(&osver, 0, sizeof(osver)); - osver.dwOSVersionInfoSize = sizeof(osver); - - detectOsState = DETECT_OS_PREVISTA; - if(GetVersionEx(&osver)) { - if(osver.dwMajorVersion >= majorVersion) - detectOsState = DETECT_OS_VISTA_OR_LATER; - } -#else - ULONGLONG cm; - OSVERSIONINFOEX osver; - - memset(&osver, 0, sizeof(osver)); - osver.dwOSVersionInfoSize = sizeof(osver); - osver.dwMajorVersion = majorVersion; - - cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL); - cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_GREATER_EQUAL); - cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); - cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); - - if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION | - VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), - cm)) + if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL)) detectOsState = DETECT_OS_VISTA_OR_LATER; else detectOsState = DETECT_OS_PREVISTA; -#endif } if(detectOsState == DETECT_OS_VISTA_OR_LATER) @@ -1012,7 +989,7 @@ static CURLcode singleipconnect(struct connectdata *conn, int rc = -1; int error = 0; bool isconnected = FALSE; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_socket_t sockfd; CURLcode result; char ipaddress[MAX_IPADR_LEN]; @@ -1111,7 +1088,10 @@ static CURLcode singleipconnect(struct connectdata *conn, CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT, NULL, 0, NULL, NULL); #elif defined(MSG_FASTOPEN) /* Linux */ - rc = 0; /* Do nothing */ + if(conn->given->flags & PROTOPT_SSL) + rc = connect(sockfd, &addr.sa_addr, addr.addrlen); + else + rc = 0; /* Do nothing */ #endif } else { @@ -1173,11 +1153,11 @@ static CURLcode singleipconnect(struct connectdata *conn, CURLcode Curl_connecthost(struct connectdata *conn, /* context */ const struct Curl_dns_entry *remotehost) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct timeval before = Curl_tvnow(); CURLcode result = CURLE_COULDNT_CONNECT; - long timeout_ms = Curl_timeleft(data, &before, TRUE); + time_t timeout_ms = Curl_timeleft(data, &before, TRUE); if(timeout_ms < 0) { /* a precaution, no need to continue if time already is up */ @@ -1232,11 +1212,11 @@ static int conn_is_conn(struct connectdata *conn, void *param) /* * Used to extract socket and connectdata struct for the most recent - * transfer on the given SessionHandle. + * transfer on the given Curl_easy. * * The returned socket will be CURL_SOCKET_BAD in case of failure! */ -curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, +curl_socket_t Curl_getconnectinfo(struct Curl_easy *data, struct connectdata **connp) { curl_socket_t sockfd; @@ -1267,24 +1247,6 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, /* only store this if the caller cares for it */ *connp = c; sockfd = c->sock[FIRSTSOCKET]; - /* we have a socket connected, let's determine if the server shut down */ - /* determine if ssl */ - if(c->ssl[FIRSTSOCKET].use) { - /* use the SSL context */ - if(!Curl_ssl_check_cxn(c)) - return CURL_SOCKET_BAD; /* FIN received */ - } -/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */ -#ifdef MSG_PEEK - else if(sockfd != CURL_SOCKET_BAD) { - /* use the socket */ - char buf; - if(recv((RECV_TYPE_ARG1)sockfd, (RECV_TYPE_ARG2)&buf, - (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) { - return CURL_SOCKET_BAD; /* FIN received */ - } - } -#endif } else return CURL_SOCKET_BAD; @@ -1292,6 +1254,33 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, return sockfd; } +/* + * Check if a connection seems to be alive. + */ +bool Curl_connalive(struct connectdata *conn) +{ + /* First determine if ssl */ + if(conn->ssl[FIRSTSOCKET].use) { + /* use the SSL context */ + if(!Curl_ssl_check_cxn(conn)) + return false; /* FIN received */ + } +/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */ +#ifdef MSG_PEEK + else if(conn->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) + return false; + else { + /* use the socket */ + char buf; + if(recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf, + (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) { + return false; /* FIN received */ + } + } +#endif + return true; +} + /* * Close a socket. * @@ -1336,7 +1325,7 @@ CURLcode Curl_socket(struct connectdata *conn, struct Curl_sockaddr_ex *addr, curl_socket_t *sockfd) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct Curl_sockaddr_ex dummy; if(!addr) @@ -1392,25 +1381,39 @@ CURLcode Curl_socket(struct connectdata *conn, } -#ifdef CURLDEBUG /* - * Curl_conncontrol() is used to set the conn->bits.close bit on or off. It - * MUST be called with the connclose() or connkeep() macros with a stated - * reason. The reason is only shown in debug builds but helps to figure out - * decision paths when connections are or aren't re-used as expected. + * Curl_conncontrol() marks streams or connection for closure. */ -void Curl_conncontrol(struct connectdata *conn, bool closeit, - const char *reason) -{ -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) reason; +void Curl_conncontrol(struct connectdata *conn, + int ctrl /* see defines in header */ +#ifdef DEBUGBUILD + , const char *reason #endif - if(closeit != conn->bits.close) { - infof(conn->data, "Marked for [%s]: %s\n", closeit?"closure":"keep alive", - reason); - + ) +{ + /* close if a connection, or a stream that isn't multiplexed */ + bool closeit = (ctrl == CONNCTRL_CONNECTION) || + ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM)); + if((ctrl == CONNCTRL_STREAM) && + (conn->handler->flags & PROTOPT_STREAM)) + DEBUGF(infof(conn->data, "Kill stream: %s\n", reason)); + else if(closeit != conn->bits.close) { + DEBUGF(infof(conn->data, "Marked for [%s]: %s\n", + closeit?"closure":"keep alive", reason)); conn->bits.close = closeit; /* the only place in the source code that should assign this bit */ } } -#endif + +/* Data received can be cached at various levels, so check them all here. */ +bool Curl_conn_data_pending(struct connectdata *conn, int sockindex) +{ + int readable; + + if(Curl_ssl_data_pending(conn, sockindex) || + Curl_recv_has_postponed_data(conn, sockindex)) + return true; + + readable = SOCKET_READABLE(conn->sock[sockindex], 0); + return (readable > 0 && (readable & CURL_CSELECT_IN)); +} diff --git a/contrib/curl/lib/connect.h b/contrib/curl/lib/connect.h index f3d4ac74..5653cb4e 100644 --- a/contrib/curl/lib/connect.h +++ b/contrib/curl/lib/connect.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -35,9 +35,9 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* generic function that returns how much time there's left to run, according to the timeouts set */ -long Curl_timeleft(struct SessionHandle *data, - struct timeval *nowp, - bool duringconnect); +time_t Curl_timeleft(struct Curl_easy *data, + struct timeval *nowp, + bool duringconnect); #define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */ #define HAPPY_EYEBALLS_TIMEOUT 200 /* milliseconds to wait between @@ -45,13 +45,18 @@ long Curl_timeleft(struct SessionHandle *data, /* * Used to extract socket and connectdata struct for the most recent - * transfer on the given SessionHandle. + * transfer on the given Curl_easy. * * The returned socket will be CURL_SOCKET_BAD in case of failure! */ -curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, +curl_socket_t Curl_getconnectinfo(struct Curl_easy *data, struct connectdata **connp); +/* + * Check if a connection seems to be alive. + */ +bool Curl_connalive(struct connectdata *conn); + #ifdef USE_WINSOCK /* When you run a program that uses the Windows Sockets API, you may experience slow performance when you copy data to a TCP server. @@ -104,21 +109,39 @@ CURLcode Curl_socket(struct connectdata *conn, void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd); -#ifdef CURLDEBUG /* - * Curl_connclose() sets the bit.close bit to TRUE with an explanation. - * Nothing else. + * Curl_conncontrol() marks the end of a connection/stream. The 'closeit' + * argument specifies if it is the end of a connection or a stream. + * + * For stream-based protocols (such as HTTP/2), a stream close will not cause + * a connection close. Other protocols will close the connection for both + * cases. + * + * It sets the bit.close bit to TRUE (with an explanation for debug builds), + * when the connection will close. */ + +#define CONNCTRL_KEEP 0 /* undo a marked closure */ +#define CONNCTRL_CONNECTION 1 +#define CONNCTRL_STREAM 2 + void Curl_conncontrol(struct connectdata *conn, - bool closeit, - const char *reason); -#define connclose(x,y) Curl_conncontrol(x,TRUE, y) -#define connkeep(x,y) Curl_conncontrol(x, FALSE, y) + int closeit +#ifdef DEBUGBUILD + , const char *reason +#endif + ); + +#ifdef DEBUGBUILD +#define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM, y) +#define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION, y) +#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP, y) #else /* if !CURLDEBUG */ - -#define connclose(x,y) (x)->bits.close = TRUE -#define connkeep(x,y) (x)->bits.close = FALSE - +#define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM) +#define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION) +#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP) #endif +bool Curl_conn_data_pending(struct connectdata *conn, int sockindex); + #endif /* HEADER_CURL_CONNECT_H */ diff --git a/contrib/curl/lib/content_encoding.c b/contrib/curl/lib/content_encoding.c index 2d30816c..c3996a11 100644 --- a/contrib/curl/lib/content_encoding.c +++ b/contrib/curl/lib/content_encoding.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -28,8 +28,8 @@ #include #include "sendf.h" #include "content_encoding.h" +#include "strdup.h" #include "curl_memory.h" - #include "memdebug.h" /* Comment this out if zlib is always going to be at least ver. 1.2.0.4 @@ -67,13 +67,13 @@ zfree_cb(voidpf opaque, voidpf ptr) static CURLcode process_zlib_error(struct connectdata *conn, z_stream *z) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(z->msg) - failf (data, "Error while processing content unencoding: %s", - z->msg); + failf(data, "Error while processing content unencoding: %s", + z->msg); else - failf (data, "Error while processing content unencoding: " - "Unknown failure within decompression software."); + failf(data, "Error while processing content unencoding: " + "Unknown failure within decompression software."); return CURLE_BAD_CONTENT_ENCODING; } @@ -314,7 +314,7 @@ Curl_unencode_gzip_write(struct connectdata *conn, #ifndef OLD_ZLIB_SUPPORT /* Support for old zlib versions is compiled away and we are running with an old version, so return an error. */ - return exit_zlib(z, &k->zlib_init, CURLE_FUNCTION_NOT_FOUND); + return exit_zlib(z, &k->zlib_init, CURLE_WRITE_ERROR); #else /* This next mess is to get around the potential case where there isn't @@ -327,14 +327,14 @@ Curl_unencode_gzip_write(struct connectdata *conn, * can handle the gzip header themselves. */ - switch (k->zlib_init) { + switch(k->zlib_init) { /* Skip over gzip header? */ case ZLIB_INIT: { /* Initial call state */ ssize_t hlen; - switch (check_gzip_header((unsigned char *)k->str, nread, &hlen)) { + switch(check_gzip_header((unsigned char *)k->str, nread, &hlen)) { case GZIP_OK: z->next_in = (Bytef *)k->str + hlen; z->avail_in = (uInt)(nread - hlen); @@ -371,18 +371,15 @@ Curl_unencode_gzip_write(struct connectdata *conn, { /* Need more gzip header data state */ ssize_t hlen; - unsigned char *oldblock = z->next_in; - z->avail_in += (uInt)nread; - z->next_in = realloc(z->next_in, z->avail_in); + z->next_in = Curl_saferealloc(z->next_in, z->avail_in); if(z->next_in == NULL) { - free(oldblock); return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY); } /* Append the new block of data to the previous one */ memcpy(z->next_in + z->avail_in - nread, k->str, nread); - switch (check_gzip_header(z->next_in, z->avail_in, &hlen)) { + switch(check_gzip_header(z->next_in, z->avail_in, &hlen)) { case GZIP_OK: /* This is the zlib stream data */ free(z->next_in); @@ -425,7 +422,7 @@ Curl_unencode_gzip_write(struct connectdata *conn, void Curl_unencode_cleanup(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SingleRequest *k = &data->req; z_stream *z = &k->z; if(k->zlib_init != ZLIB_UNINIT) diff --git a/contrib/curl/lib/cookie.c b/contrib/curl/lib/cookie.c index 01ce270b..94628433 100644 --- a/contrib/curl/lib/cookie.c +++ b/contrib/curl/lib/cookie.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,13 +26,13 @@ RECEIVING COOKIE INFORMATION ============================ -struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, +struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, const char *file, struct CookieInfo *inc, bool newsession); Inits a cookie struct to store data in a local file. This is always called before any cookies are set. -struct Cookie *Curl_cookie_add(struct SessionHandle *data, +struct Cookie *Curl_cookie_add(struct Curl_easy *data, struct CookieInfo *c, bool httpheader, char *lineptr, const char *domain, const char *path); @@ -90,13 +90,12 @@ Example set of cookies: #include "urldata.h" #include "cookie.h" -#include "strequal.h" #include "strtok.h" #include "sendf.h" #include "slist.h" #include "share.h" #include "strtoofft.h" -#include "rawstr.h" +#include "strcase.h" #include "curl_memrchr.h" #include "inet_pton.h" @@ -126,7 +125,7 @@ static bool tailmatch(const char *cooke_domain, const char *hostname) if(hostname_len < cookie_domain_len) return FALSE; - if(!Curl_raw_equal(cooke_domain, hostname+hostname_len-cookie_domain_len)) + if(!strcasecompare(cooke_domain, hostname+hostname_len-cookie_domain_len)) return FALSE; /* A lead char of cookie_domain is not '.'. @@ -147,12 +146,12 @@ static bool tailmatch(const char *cooke_domain, const char *hostname) * matching cookie path and url path * RFC6265 5.1.4 Paths and Path-Match */ -static bool pathmatch(const char* cookie_path, const char* request_uri) +static bool pathmatch(const char *cookie_path, const char *request_uri) { size_t cookie_path_len; size_t uri_path_len; - char* uri_path = NULL; - char* pos; + char *uri_path = NULL; + char *pos; bool ret = FALSE; /* cookie_path must not have last '/' separator. ex: /sample */ @@ -260,7 +259,7 @@ static char *sanitize_cookie_path(const char *cookie_path) * * NOTE: OOM or cookie parsing failures are ignored. */ -void Curl_cookie_loadfiles(struct SessionHandle *data) +void Curl_cookie_loadfiles(struct Curl_easy *data) { struct curl_slist *list = data->change.cookielist; if(list) { @@ -362,7 +361,7 @@ static bool isip(const char *domain) ***************************************************************************/ struct Cookie * -Curl_cookie_add(struct SessionHandle *data, +Curl_cookie_add(struct Curl_easy *data, /* The 'data' pointer here may be NULL at times, and thus must only be used very carefully for things that can deal with data being NULL. Such as infof() and similar */ @@ -469,9 +468,9 @@ Curl_cookie_add(struct SessionHandle *data, /* this was a "=" with no content, and we must allow 'secure' and 'httponly' specified this weirdly */ done = TRUE; - if(Curl_raw_equal("secure", name)) + if(strcasecompare("secure", name)) co->secure = TRUE; - else if(Curl_raw_equal("httponly", name)) + else if(strcasecompare("httponly", name)) co->httponly = TRUE; else if(sep) /* there was a '=' so we're not done parsing this field */ @@ -479,7 +478,7 @@ Curl_cookie_add(struct SessionHandle *data, } if(done) ; - else if(Curl_raw_equal("path", name)) { + else if(strcasecompare("path", name)) { strstore(&co->path, whatptr); if(!co->path) { badcookie = TRUE; /* out of memory bad */ @@ -491,9 +490,8 @@ Curl_cookie_add(struct SessionHandle *data, break; } } - else if(Curl_raw_equal("domain", name)) { + else if(strcasecompare("domain", name)) { bool is_ip; - const char *dotp; /* Now, we make sure that our host is within the given domain, or the given domain is not valid and thus cannot be set. */ @@ -501,12 +499,22 @@ Curl_cookie_add(struct SessionHandle *data, if('.' == whatptr[0]) whatptr++; /* ignore preceding dot */ - is_ip = isip(domain ? domain : whatptr); +#ifndef USE_LIBPSL + /* + * Without PSL we don't know when the incoming cookie is set on a + * TLD or otherwise "protected" suffix. To reduce risk, we require a + * dot OR the exact host name being "localhost". + */ + { + const char *dotp; + /* check for more dots */ + dotp = strchr(whatptr, '.'); + if(!dotp && !strcasecompare("localhost", whatptr)) + domain=":"; + } +#endif - /* check for more dots */ - dotp = strchr(whatptr, '.'); - if(!dotp) - domain=":"; + is_ip = isip(domain ? domain : whatptr); if(!domain || (is_ip && !strcmp(whatptr, domain)) @@ -529,14 +537,14 @@ Curl_cookie_add(struct SessionHandle *data, whatptr); } } - else if(Curl_raw_equal("version", name)) { + else if(strcasecompare("version", name)) { strstore(&co->version, whatptr); if(!co->version) { badcookie = TRUE; break; } } - else if(Curl_raw_equal("max-age", name)) { + else if(strcasecompare("max-age", name)) { /* Defined in RFC2109: Optional. The Max-Age attribute defines the lifetime of the @@ -552,7 +560,7 @@ Curl_cookie_add(struct SessionHandle *data, break; } } - else if(Curl_raw_equal("expires", name)) { + else if(strcasecompare("expires", name)) { strstore(&co->expirestr, whatptr); if(!co->expirestr) { badcookie = TRUE; @@ -713,7 +721,7 @@ Curl_cookie_add(struct SessionHandle *data, As far as I can see, it is set to true when the cookie says .domain.com and to false when the domain is complete www.domain.com */ - co->tailmatch = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE; + co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE; break; case 2: /* It turns out, that sometimes the file format allows the path @@ -742,7 +750,7 @@ Curl_cookie_add(struct SessionHandle *data, fields++; /* add a field and fall down to secure */ /* FALLTHROUGH */ case 3: - co->secure = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE; + co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE; break; case 4: co->expires = curlx_strtoofft(ptr, NULL, 10); @@ -799,8 +807,8 @@ Curl_cookie_add(struct SessionHandle *data, /* Check if the domain is a Public Suffix and if yes, ignore the cookie. This needs a libpsl compiled with builtin data. */ if(domain && co->domain && !isip(co->domain)) { - if(((psl = psl_builtin()) != NULL) - && !psl_is_cookie_domain_acceptable(psl, domain, co->domain)) { + psl = psl_builtin(); + if(psl && !psl_is_cookie_domain_acceptable(psl, domain, co->domain)) { infof(data, "cookie '%s' dropped, domain '%s' must not set cookies for '%s'\n", co->name, domain, co->domain); @@ -813,11 +821,12 @@ Curl_cookie_add(struct SessionHandle *data, clist = c->cookies; replace_old = FALSE; while(clist) { - if(Curl_raw_equal(clist->name, co->name)) { + if(strcasecompare(clist->name, co->name)) { /* the names are identical */ if(clist->domain && co->domain) { - if(Curl_raw_equal(clist->domain, co->domain)) + if(strcasecompare(clist->domain, co->domain) && + (clist->tailmatch == co->tailmatch)) /* The domains are identical */ replace_old=TRUE; } @@ -828,7 +837,7 @@ Curl_cookie_add(struct SessionHandle *data, /* the domains were identical */ if(clist->spath && co->spath) { - if(Curl_raw_equal(clist->spath, co->spath)) { + if(strcasecompare(clist->spath, co->spath)) { replace_old = TRUE; } else @@ -902,6 +911,35 @@ Curl_cookie_add(struct SessionHandle *data, return co; } +/* + * get_line() makes sure to only return complete whole lines that fit in 'len' + * bytes and end with a newline. + */ +static char *get_line(char *buf, int len, FILE *input) +{ + bool partial = FALSE; + while(1) { + char *b = fgets(buf, len, input); + if(b) { + size_t rlen = strlen(b); + if(rlen && (b[rlen-1] == '\n')) { + if(partial) { + partial = FALSE; + continue; + } + return b; + } + else + /* read a partial, discard the next piece that ends with newline */ + partial = TRUE; + } + else + break; + } + return NULL; +} + + /***************************************************************************** * * Curl_cookie_init() @@ -913,7 +951,7 @@ Curl_cookie_add(struct SessionHandle *data, * * Returns NULL on out of memory. Invalid cookies are ignored. ****************************************************************************/ -struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, +struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, const char *file, struct CookieInfo *inc, bool newsession) @@ -938,7 +976,7 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, } c->running = FALSE; /* this is not running, this is init */ - if(file && strequal(file, "-")) { + if(file && !strcmp(file, "-")) { fp = stdin; fromfile=FALSE; } @@ -958,7 +996,7 @@ struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, line = malloc(MAX_COOKIE_LINE); if(!line) goto fail; - while(fgets(line, MAX_COOKIE_LINE, fp)) { + while(get_line(line, MAX_COOKIE_LINE, fp)) { if(checkprefix("Set-Cookie:", line)) { /* This is a cookie line, get it! */ lineptr=&line[11]; @@ -1023,6 +1061,40 @@ static int cookie_sort(const void *p1, const void *p2) return 0; } +#define CLONE(field) \ + do { \ + if(src->field) { \ + d->field = strdup(src->field); \ + if(!d->field) \ + goto fail; \ + } \ + } while(0) + +static struct Cookie *dup_cookie(struct Cookie *src) +{ + struct Cookie *d = calloc(sizeof(struct Cookie), 1); + if(d) { + CLONE(expirestr); + CLONE(domain); + CLONE(path); + CLONE(spath); + CLONE(name); + CLONE(value); + CLONE(maxage); + CLONE(version); + d->expires = src->expires; + d->tailmatch = src->tailmatch; + d->secure = src->secure; + d->livecookie = src->livecookie; + d->httponly = src->httponly; + } + return d; + + fail: + freecookie(d); + return NULL; +} + /***************************************************************************** * * Curl_cookie_getlist() @@ -1067,7 +1139,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, /* now check if the domain is correct */ if(!co->domain || (co->tailmatch && !is_ip && tailmatch(co->domain, host)) || - ((!co->tailmatch || is_ip) && Curl_raw_equal(host, co->domain)) ) { + ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) { /* the right part of the host matches the domain stuff in the cookie data */ @@ -1078,11 +1150,8 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, /* and now, we know this is a match and we should create an entry for the return-linked-list */ - newco = malloc(sizeof(struct Cookie)); + newco = dup_cookie(co); if(newco) { - /* first, copy the whole source cookie: */ - memcpy(newco, co, sizeof(struct Cookie)); - /* then modify our next */ newco->next = mainco; @@ -1094,12 +1163,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, else { fail: /* failure, clear up the allocated chain and return NULL */ - while(mainco) { - co = mainco->next; - free(mainco); - mainco = co; - } - + Curl_cookie_freelist(mainco); return NULL; } } @@ -1151,7 +1215,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, void Curl_cookie_clearall(struct CookieInfo *cookies) { if(cookies) { - Curl_cookie_freelist(cookies->cookies, TRUE); + Curl_cookie_freelist(cookies->cookies); cookies->cookies = NULL; cookies->numcookies = 0; } @@ -1163,21 +1227,14 @@ void Curl_cookie_clearall(struct CookieInfo *cookies) * * Free a list of cookies previously returned by Curl_cookie_getlist(); * - * The 'cookiestoo' argument tells this function whether to just free the - * list or actually also free all cookies within the list as well. - * ****************************************************************************/ -void Curl_cookie_freelist(struct Cookie *co, bool cookiestoo) +void Curl_cookie_freelist(struct Cookie *co) { struct Cookie *next; while(co) { next = co->next; - if(cookiestoo) - freecookie(co); - else - free(co); /* we only free the struct since the "members" are all just - pointed out in the main cookie list! */ + freecookie(co); co = next; } } @@ -1232,7 +1289,7 @@ void Curl_cookie_cleanup(struct CookieInfo *c) { if(c) { free(c->filename); - Curl_cookie_freelist(c->cookies, TRUE); + Curl_cookie_freelist(c->cookies); free(c); /* free the base struct as well */ } } @@ -1290,7 +1347,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) /* at first, remove expired cookies */ remove_expired(c); - if(strequal("-", dumphere)) { + if(!strcmp("-", dumphere)) { /* use stdout */ out = stdout; use_stdout=TRUE; @@ -1314,7 +1371,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) fprintf(out, "#\n# Fatal libcurl error\n"); if(!use_stdout) fclose(out); - return 1; + return 1; } fprintf(out, "%s\n", format_ptr); free(format_ptr); @@ -1326,7 +1383,7 @@ static int cookie_output(struct CookieInfo *c, const char *dumphere) return 0; } -struct curl_slist *Curl_cookie_list(struct SessionHandle *data) +struct curl_slist *Curl_cookie_list(struct Curl_easy *data) { struct curl_slist *list = NULL; struct curl_slist *beg; @@ -1357,7 +1414,7 @@ struct curl_slist *Curl_cookie_list(struct SessionHandle *data) return list; } -void Curl_flush_cookies(struct SessionHandle *data, int cleanup) +void Curl_flush_cookies(struct Curl_easy *data, int cleanup) { if(data->set.str[STRING_COOKIEJAR]) { if(data->change.cookielist) { diff --git a/contrib/curl/lib/cookie.h b/contrib/curl/lib/cookie.h index 74a9224e..a9a45785 100644 --- a/contrib/curl/lib/cookie.h +++ b/contrib/curl/lib/cookie.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -70,19 +70,19 @@ struct CookieInfo { #define MAX_NAME 1024 #define MAX_NAME_TXT "1023" -struct SessionHandle; +struct Curl_easy; /* * Add a cookie to the internal list of cookies. The domain and path arguments * are only used if the header boolean is TRUE. */ -struct Cookie *Curl_cookie_add(struct SessionHandle *data, +struct Cookie *Curl_cookie_add(struct Curl_easy *data, struct CookieInfo *, bool header, char *lineptr, const char *domain, const char *path); struct Cookie *Curl_cookie_getlist(struct CookieInfo *, const char *, const char *, bool); -void Curl_cookie_freelist(struct Cookie *cookies, bool cookiestoo); +void Curl_cookie_freelist(struct Cookie *cookies); void Curl_cookie_clearall(struct CookieInfo *cookies); void Curl_cookie_clearsess(struct CookieInfo *cookies); @@ -93,12 +93,12 @@ void Curl_cookie_clearsess(struct CookieInfo *cookies); #define Curl_cookie_cleanup(x) Curl_nop_stmt #define Curl_flush_cookies(x,y) Curl_nop_stmt #else -void Curl_flush_cookies(struct SessionHandle *data, int cleanup); +void Curl_flush_cookies(struct Curl_easy *data, int cleanup); void Curl_cookie_cleanup(struct CookieInfo *); -struct CookieInfo *Curl_cookie_init(struct SessionHandle *data, +struct CookieInfo *Curl_cookie_init(struct Curl_easy *data, const char *, struct CookieInfo *, bool); -struct curl_slist *Curl_cookie_list(struct SessionHandle *data); -void Curl_cookie_loadfiles(struct SessionHandle *data); +struct curl_slist *Curl_cookie_list(struct Curl_easy *data); +void Curl_cookie_loadfiles(struct Curl_easy *data); #endif #endif /* HEADER_CURL_COOKIE_H */ diff --git a/contrib/curl/lib/curl_addrinfo.c b/contrib/curl/lib/curl_addrinfo.c index 8fa0c84c..3dbfb3eb 100644 --- a/contrib/curl/lib/curl_addrinfo.c +++ b/contrib/curl/lib/curl_addrinfo.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -47,6 +47,8 @@ # define in_addr_t unsigned long #endif +#include + #include "curl_addrinfo.h" #include "inet_pton.h" #include "warnless.h" @@ -146,7 +148,8 @@ Curl_getaddrinfo_ex(const char *nodename, if((size_t)ai->ai_addrlen < ss_size) continue; - if((ca = malloc(sizeof(Curl_addrinfo))) == NULL) { + ca = malloc(sizeof(Curl_addrinfo)); + if(!ca) { error = EAI_MEMORY; break; } @@ -163,7 +166,8 @@ Curl_getaddrinfo_ex(const char *nodename, ca->ai_canonname = NULL; ca->ai_next = NULL; - if((ca->ai_addr = malloc(ss_size)) == NULL) { + ca->ai_addr = malloc(ss_size); + if(!ca->ai_addr) { error = EAI_MEMORY; free(ca); break; @@ -171,7 +175,8 @@ Curl_getaddrinfo_ex(const char *nodename, memcpy(ca->ai_addr, ai->ai_addr, ss_size); if(ai->ai_canonname != NULL) { - if((ca->ai_canonname = strdup(ai->ai_canonname)) == NULL) { + ca->ai_canonname = strdup(ai->ai_canonname); + if(!ca->ai_canonname) { error = EAI_MEMORY; free(ca->ai_addr); free(ca); @@ -286,21 +291,24 @@ Curl_he2ai(const struct hostent *he, int port) size_t ss_size; #ifdef ENABLE_IPV6 if(he->h_addrtype == AF_INET6) - ss_size = sizeof (struct sockaddr_in6); + ss_size = sizeof(struct sockaddr_in6); else #endif - ss_size = sizeof (struct sockaddr_in); + ss_size = sizeof(struct sockaddr_in); - if((ai = calloc(1, sizeof(Curl_addrinfo))) == NULL) { + ai = calloc(1, sizeof(Curl_addrinfo)); + if(!ai) { result = CURLE_OUT_OF_MEMORY; break; } - if((ai->ai_canonname = strdup(he->h_name)) == NULL) { + ai->ai_canonname = strdup(he->h_name); + if(!ai->ai_canonname) { result = CURLE_OUT_OF_MEMORY; free(ai); break; } - if((ai->ai_addr = calloc(1, ss_size)) == NULL) { + ai->ai_addr = calloc(1, ss_size); + if(!ai->ai_addr) { result = CURLE_OUT_OF_MEMORY; free(ai->ai_canonname); free(ai); @@ -325,7 +333,7 @@ Curl_he2ai(const struct hostent *he, int port) /* leave the rest of the struct filled with zero */ - switch (ai->ai_family) { + switch(ai->ai_family) { case AF_INET: addr = (void *)ai->ai_addr; /* storage area for this info */ @@ -475,34 +483,48 @@ Curl_addrinfo *Curl_str2addr(char *address, int port) /** * Given a path to a Unix domain socket, return a newly allocated Curl_addrinfo * struct initialized with this path. + * Set '*longpath' to TRUE if the error is a too long path. */ -Curl_addrinfo *Curl_unix2addr(const char *path) +Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract) { Curl_addrinfo *ai; struct sockaddr_un *sa_un; size_t path_len; + *longpath = FALSE; + ai = calloc(1, sizeof(Curl_addrinfo)); if(!ai) return NULL; - if((ai->ai_addr = calloc(1, sizeof(struct sockaddr_un))) == NULL) { + ai->ai_addr = calloc(1, sizeof(struct sockaddr_un)); + if(!ai->ai_addr) { free(ai); return NULL; } + + sa_un = (void *) ai->ai_addr; + sa_un->sun_family = AF_UNIX; + /* sun_path must be able to store the NUL-terminated path */ - path_len = strlen(path); - if(path_len >= sizeof(sa_un->sun_path)) { + path_len = strlen(path) + 1; + if(path_len > sizeof(sa_un->sun_path)) { free(ai->ai_addr); free(ai); + *longpath = TRUE; return NULL; } ai->ai_family = AF_UNIX; ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */ - ai->ai_addrlen = (curl_socklen_t) sizeof(struct sockaddr_un); - sa_un = (void *) ai->ai_addr; - sa_un->sun_family = AF_UNIX; - memcpy(sa_un->sun_path, path, path_len + 1); /* copy NUL byte */ + ai->ai_addrlen = (curl_socklen_t) + ((offsetof(struct sockaddr_un, sun_path) + path_len) & 0x7FFFFFFF); + + /* Abstract Unix domain socket have NULL prefix instead of suffix */ + if(abstract) + memcpy(sa_un->sun_path + 1, path, path_len - 1); + else + memcpy(sa_un->sun_path, path, path_len); /* copy NUL byte */ + return ai; } #endif @@ -563,3 +585,32 @@ curl_dogetaddrinfo(const char *hostname, } #endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */ +#if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS) +/* + * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and Mac OS X + * 10.11.5. + */ +void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port) +{ + Curl_addrinfo *ca; + struct sockaddr_in *addr; +#ifdef ENABLE_IPV6 + struct sockaddr_in6 *addr6; +#endif + for(ca = addrinfo; ca != NULL; ca = ca->ai_next) { + switch(ca->ai_family) { + case AF_INET: + addr = (void *)ca->ai_addr; /* storage area for this info */ + addr->sin_port = htons((unsigned short)port); + break; + +#ifdef ENABLE_IPV6 + case AF_INET6: + addr6 = (void *)ca->ai_addr; /* storage area for this info */ + addr6->sin6_port = htons((unsigned short)port); + break; +#endif + } + } +} +#endif diff --git a/contrib/curl/lib/curl_addrinfo.h b/contrib/curl/lib/curl_addrinfo.h index 01f28647..8f6f3d10 100644 --- a/contrib/curl/lib/curl_addrinfo.h +++ b/contrib/curl/lib/curl_addrinfo.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -80,7 +80,7 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port); Curl_addrinfo *Curl_str2addr(char *dotted, int port); #ifdef USE_UNIX_SOCKETS -Curl_addrinfo *Curl_unix2addr(const char *path); +Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract); #endif #if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \ @@ -99,4 +99,12 @@ curl_dogetaddrinfo(const char *hostname, int line, const char *source); #endif +#ifdef HAVE_GETADDRINFO +#ifdef USE_RESOLVE_ON_IPS +void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port); +#else +#define Curl_addrinfo_set_port(x,y) +#endif +#endif + #endif /* HEADER_CURL_ADDRINFO_H */ diff --git a/contrib/curl/lib/curl_base64.h b/contrib/curl/lib/curl_base64.h index c2624176..7e9fc260 100644 --- a/contrib/curl/lib/curl_base64.h +++ b/contrib/curl/lib/curl_base64.h @@ -22,10 +22,10 @@ * ***************************************************************************/ -CURLcode Curl_base64_encode(struct SessionHandle *data, +CURLcode Curl_base64_encode(struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen); -CURLcode Curl_base64url_encode(struct SessionHandle *data, +CURLcode Curl_base64url_encode(struct Curl_easy *data, const char *inputbuff, size_t insize, char **outptr, size_t *outlen); diff --git a/contrib/curl/lib/curl_config.h.cmake b/contrib/curl/lib/curl_config.h.cmake index 6b5070a8..49c1b8a2 100644 --- a/contrib/curl/lib/curl_config.h.cmake +++ b/contrib/curl/lib/curl_config.h.cmake @@ -67,7 +67,7 @@ #cmakedefine CURL_DISABLE_VERBOSE_STRINGS 1 /* to make a symbol visible */ -#cmakedefine CURL_EXTERN_SYMBOL 1 +#cmakedefine CURL_EXTERN_SYMBOL ${CURL_EXTERN_SYMBOL} /* Ensure using CURL_EXTERN_SYMBOL is possible */ #ifndef CURL_EXTERN_SYMBOL #define CURL_EXTERN_SYMBOL @@ -518,6 +518,15 @@ /* Define to 1 if you have the send function. */ #cmakedefine HAVE_SEND 1 +/* Define to 1 if you have the 'fsetxattr' function. */ +#cmakedefine HAVE_FSETXATTR 1 + +/* fsetxattr() takes 5 args */ +#cmakedefine HAVE_FSETXATTR_5 1 + +/* fsetxattr() takes 6 args */ +#cmakedefine HAVE_FSETXATTR_6 1 + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SETJMP_H 1 @@ -906,6 +915,9 @@ /* Define if you want to enable POSIX threaded DNS lookup */ #cmakedefine USE_THREADS_POSIX 1 +/* Define if you want to enable WIN32 threaded DNS lookup */ +#cmakedefine USE_THREADS_WIN32 1 + /* Define to disable non-blocking sockets. */ #cmakedefine USE_BLOCKING_SOCKETS 1 @@ -915,6 +927,9 @@ /* if PolarSSL is enabled */ #cmakedefine USE_POLARSSL 1 +/* if mbedTLS is enabled */ +#cmakedefine USE_MBEDTLS 1 + /* if libSSH2 is in use */ #cmakedefine USE_LIBSSH2 1 @@ -930,11 +945,13 @@ /* if OpenSSL is in use */ #cmakedefine USE_OPENSSL 1 +/* to enable NGHTTP2 */ +#cmakedefine USE_NGHTTP2 1 + /* if Unix domain sockets are enabled */ #cmakedefine USE_UNIX_SOCKETS -/* Define to 1 if you are building a Windows target without large file - support. */ +/* Define to 1 if you are building a Windows target with large file support. */ #cmakedefine USE_WIN32_LARGE_FILES 1 /* to enable SSPI support */ diff --git a/contrib/curl/lib/curl_des.c b/contrib/curl/lib/curl_des.c index 421c9f76..b123a00f 100644 --- a/contrib/curl/lib/curl_des.c +++ b/contrib/curl/lib/curl_des.c @@ -34,7 +34,7 @@ * * The function is a port of the Java based oddParity() function over at: * - * http://davenport.sourceforge.net/ntlm.html + * https://davenport.sourceforge.io/ntlm.html * * Parameters: * diff --git a/contrib/curl/lib/curl_endian.c b/contrib/curl/lib/curl_endian.c index 76deca6a..c2d21de5 100644 --- a/contrib/curl/lib/curl_endian.c +++ b/contrib/curl/lib/curl_endian.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -37,7 +37,7 @@ * * Returns the integer. */ -unsigned short Curl_read16_le(unsigned char *buf) +unsigned short Curl_read16_le(const unsigned char *buf) { return (unsigned short)(((unsigned short)buf[0]) | ((unsigned short)buf[1] << 8)); @@ -56,7 +56,7 @@ unsigned short Curl_read16_le(unsigned char *buf) * * Returns the integer. */ -unsigned int Curl_read32_le(unsigned char *buf) +unsigned int Curl_read32_le(const unsigned char *buf) { return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) | ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24); @@ -77,7 +77,7 @@ unsigned int Curl_read32_le(unsigned char *buf) * Returns the integer. */ #if defined(HAVE_LONGLONG) -unsigned long long Curl_read64_le(unsigned char *buf) +unsigned long long Curl_read64_le(const unsigned char *buf) { return ((unsigned long long)buf[0]) | ((unsigned long long)buf[1] << 8) | @@ -89,7 +89,7 @@ unsigned long long Curl_read64_le(unsigned char *buf) ((unsigned long long)buf[7] << 56); } #else -unsigned __int64 Curl_read64_le(unsigned char *buf) +unsigned __int64 Curl_read64_le(const unsigned char *buf) { return ((unsigned __int64)buf[0]) | ((unsigned __int64)buf[1] << 8) | ((unsigned __int64)buf[2] << 16) | ((unsigned __int64)buf[3] << 24) | @@ -113,7 +113,7 @@ unsigned __int64 Curl_read64_le(unsigned char *buf) * * Returns the integer. */ -unsigned short Curl_read16_be(unsigned char *buf) +unsigned short Curl_read16_be(const unsigned char *buf) { return (unsigned short)(((unsigned short)buf[0] << 8) | ((unsigned short)buf[1])); @@ -132,7 +132,7 @@ unsigned short Curl_read16_be(unsigned char *buf) * * Returns the integer. */ -unsigned int Curl_read32_be(unsigned char *buf) +unsigned int Curl_read32_be(const unsigned char *buf) { return ((unsigned int)buf[0] << 24) | ((unsigned int)buf[1] << 16) | ((unsigned int)buf[2] << 8) | ((unsigned int)buf[3]); @@ -153,7 +153,7 @@ unsigned int Curl_read32_be(unsigned char *buf) * Returns the integer. */ #if defined(HAVE_LONGLONG) -unsigned long long Curl_read64_be(unsigned char *buf) +unsigned long long Curl_read64_be(const unsigned char *buf) { return ((unsigned long long)buf[0] << 56) | ((unsigned long long)buf[1] << 48) | @@ -165,7 +165,7 @@ unsigned long long Curl_read64_be(unsigned char *buf) ((unsigned long long)buf[7]); } #else -unsigned __int64 Curl_read64_be(unsigned char *buf) +unsigned __int64 Curl_read64_be(const unsigned char *buf) { return ((unsigned __int64)buf[0] << 56) | ((unsigned __int64)buf[1] << 48) | ((unsigned __int64)buf[2] << 40) | ((unsigned __int64)buf[3] << 32) | diff --git a/contrib/curl/lib/curl_endian.h b/contrib/curl/lib/curl_endian.h index df8398c8..8a2b07ad 100644 --- a/contrib/curl/lib/curl_endian.h +++ b/contrib/curl/lib/curl_endian.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,32 +23,32 @@ ***************************************************************************/ /* Converts a 16-bit integer from little endian */ -unsigned short Curl_read16_le(unsigned char *buf); +unsigned short Curl_read16_le(const unsigned char *buf); /* Converts a 32-bit integer from little endian */ -unsigned int Curl_read32_le(unsigned char *buf); +unsigned int Curl_read32_le(const unsigned char *buf); #if (CURL_SIZEOF_CURL_OFF_T > 4) /* Converts a 64-bit integer from little endian */ #if defined(HAVE_LONGLONG) -unsigned long long Curl_read64_le(unsigned char *buf); +unsigned long long Curl_read64_le(const unsigned char *buf); #else -unsigned __int64 Curl_read64_le(unsigned char *buf); +unsigned __int64 Curl_read64_le(const unsigned char *buf); #endif #endif /* Converts a 16-bit integer from big endian */ -unsigned short Curl_read16_be(unsigned char *buf); +unsigned short Curl_read16_be(const unsigned char *buf); /* Converts a 32-bit integer from big endian */ -unsigned int Curl_read32_be(unsigned char *buf); +unsigned int Curl_read32_be(const unsigned char *buf); #if (CURL_SIZEOF_CURL_OFF_T > 4) /* Converts a 64-bit integer from big endian */ #if defined(HAVE_LONGLONG) -unsigned long long Curl_read64_be(unsigned char *buf); +unsigned long long Curl_read64_be(const unsigned char *buf); #else -unsigned __int64 Curl_read64_be(unsigned char *buf); +unsigned __int64 Curl_read64_be(const unsigned char *buf); #endif #endif diff --git a/contrib/curl/lib/curl_gethostname.c b/contrib/curl/lib/curl_gethostname.c index 2591fd88..8337c72e 100644 --- a/contrib/curl/lib/curl_gethostname.c +++ b/contrib/curl/lib/curl_gethostname.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -48,8 +48,8 @@ * For libcurl static library release builds no overriding takes place. */ -int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen) { - +int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen) +{ #ifndef HAVE_GETHOSTNAME /* Allow compilation and return failure when unavailable */ @@ -59,7 +59,7 @@ int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen) { #else int err; - char* dot; + char *dot; #ifdef DEBUGBUILD diff --git a/contrib/curl/lib/curl_gssapi.c b/contrib/curl/lib/curl_gssapi.c index 6f9121e4..83f3fa0c 100644 --- a/contrib/curl/lib/curl_gssapi.c +++ b/contrib/curl/lib/curl_gssapi.c @@ -33,7 +33,7 @@ static char krb5_oid_bytes[] = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"; gss_OID_desc Curl_krb5_mech_oid = { 9, &krb5_oid_bytes }; OM_uint32 Curl_gss_init_sec_context( - struct SessionHandle *data, + struct Curl_easy *data, OM_uint32 *minor_status, gss_ctx_id_t *context, gss_name_t target_name, @@ -94,7 +94,7 @@ static size_t display_gss_error(OM_uint32 status, int type, if(GSS_LOG_BUFFER_LEN > len + status_string.length + 3) { len += snprintf(buf + len, GSS_LOG_BUFFER_LEN - len, "%.*s. ", (int)status_string.length, - (char*)status_string.value); + (char *)status_string.value); } gss_release_buffer(&min_stat, &status_string); } while(!GSS_ERROR(maj_stat) && msg_ctx != 0); @@ -114,7 +114,7 @@ static size_t display_gss_error(OM_uint32 status, int type, * major [in] - The major status code. * minor [in] - The minor status code. */ -void Curl_gss_log_error(struct SessionHandle *data, const char *prefix, +void Curl_gss_log_error(struct Curl_easy *data, const char *prefix, OM_uint32 major, OM_uint32 minor) { char buf[GSS_LOG_BUFFER_LEN]; diff --git a/contrib/curl/lib/curl_gssapi.h b/contrib/curl/lib/curl_gssapi.h index 42fd1e41..9700a281 100644 --- a/contrib/curl/lib/curl_gssapi.h +++ b/contrib/curl/lib/curl_gssapi.h @@ -44,7 +44,7 @@ extern gss_OID_desc Curl_krb5_mech_oid; /* Common method for using GSS-API */ OM_uint32 Curl_gss_init_sec_context( - struct SessionHandle *data, + struct Curl_easy *data, OM_uint32 *minor_status, gss_ctx_id_t *context, gss_name_t target_name, @@ -56,7 +56,7 @@ OM_uint32 Curl_gss_init_sec_context( OM_uint32 *ret_flags); /* Helper to log a GSS-API error status */ -void Curl_gss_log_error(struct SessionHandle *data, const char *prefix, +void Curl_gss_log_error(struct Curl_easy *data, const char *prefix, OM_uint32 major, OM_uint32 minor); /* Provide some definitions missing in old headers */ diff --git a/contrib/curl/lib/curl_hmac.h b/contrib/curl/lib/curl_hmac.h index 41703b42..756dc9e4 100644 --- a/contrib/curl/lib/curl_hmac.h +++ b/contrib/curl/lib/curl_hmac.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,11 +24,11 @@ #ifndef CURL_DISABLE_CRYPTO_AUTH -typedef void (* HMAC_hinit_func)(void * context); -typedef void (* HMAC_hupdate_func)(void * context, - const unsigned char * data, +typedef void (* HMAC_hinit_func)(void *context); +typedef void (* HMAC_hupdate_func)(void *context, + const unsigned char *data, unsigned int len); -typedef void (* HMAC_hfinal_func)(unsigned char * result, void * context); +typedef void (* HMAC_hfinal_func)(unsigned char *result, void *context); /* Per-hash function HMAC parameters. */ @@ -46,21 +46,21 @@ typedef struct { /* HMAC computation context. */ typedef struct { - const HMAC_params * hmac_hash; /* Hash function definition. */ - void * hmac_hashctxt1; /* Hash function context 1. */ - void * hmac_hashctxt2; /* Hash function context 2. */ + const HMAC_params *hmac_hash; /* Hash function definition. */ + void *hmac_hashctxt1; /* Hash function context 1. */ + void *hmac_hashctxt2; /* Hash function context 2. */ } HMAC_context; /* Prototypes. */ -HMAC_context * Curl_HMAC_init(const HMAC_params * hashparams, - const unsigned char * key, +HMAC_context * Curl_HMAC_init(const HMAC_params *hashparams, + const unsigned char *key, unsigned int keylen); -int Curl_HMAC_update(HMAC_context * context, - const unsigned char * data, +int Curl_HMAC_update(HMAC_context *context, + const unsigned char *data, unsigned int len); -int Curl_HMAC_final(HMAC_context * context, unsigned char * result); +int Curl_HMAC_final(HMAC_context *context, unsigned char *result); #endif diff --git a/contrib/curl/lib/curl_ntlm_core.c b/contrib/curl/lib/curl_ntlm_core.c index ea7548dd..e02983ce 100644 --- a/contrib/curl/lib/curl_ntlm_core.c +++ b/contrib/curl/lib/curl_ntlm_core.c @@ -27,7 +27,7 @@ /* * NTLM details: * - * http://davenport.sourceforge.net/ntlm.html + * https://davenport.sourceforge.io/ntlm.html * https://www.innovation.ch/java/ntlm.html */ @@ -76,6 +76,11 @@ # define MD5_DIGEST_LENGTH 16 # define MD4_DIGEST_LENGTH 16 +#elif defined(USE_MBEDTLS) + +# include +# include + #elif defined(USE_NSS) # include @@ -100,7 +105,7 @@ #include "urldata.h" #include "non-ascii.h" -#include "rawstr.h" +#include "strcase.h" #include "curl_ntlm_core.h" #include "curl_md5.h" #include "curl_hmac.h" @@ -188,6 +193,26 @@ static void setup_des_key(const unsigned char *key_56, gcry_cipher_setkey(*des, key, sizeof(key)); } +#elif defined(USE_MBEDTLS) + +static bool encrypt_des(const unsigned char *in, unsigned char *out, + const unsigned char *key_56) +{ + mbedtls_des_context ctx; + char key[8]; + + /* Expand the 56-bit key to 64-bits */ + extend_key_56_to_64(key_56, key); + + /* Set the key parity to odd */ + mbedtls_des_key_set_parity((unsigned char *) key); + + /* Perform the encryption */ + mbedtls_des_init(&ctx); + mbedtls_des_setkey_enc(&ctx, (unsigned char *) key); + return mbedtls_des_crypt_ecb(&ctx, in, out) == 0; +} + #elif defined(USE_NSS) /* @@ -400,8 +425,8 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys, setup_des_key(keys + 14, &des); gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8); gcry_cipher_close(des); -#elif defined(USE_NSS) || defined(USE_DARWINSSL) || defined(USE_OS400CRYPTO) \ - || defined(USE_WIN32_CRYPTO) +#elif defined(USE_MBEDTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) \ + || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) encrypt_des(plaintext, results, keys); encrypt_des(plaintext, results + 8, keys + 7); encrypt_des(plaintext, results + 16, keys + 14); @@ -411,7 +436,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys, /* * Set up lanmanager hashed password */ -CURLcode Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, +CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data, const char *password, unsigned char *lmbuffer /* 21 bytes */) { @@ -464,8 +489,8 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, setup_des_key(pw + 7, &des); gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8); gcry_cipher_close(des); -#elif defined(USE_NSS) || defined(USE_DARWINSSL) || defined(USE_OS400CRYPTO) \ - || defined(USE_WIN32_CRYPTO) +#elif defined(USE_MBEDTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) \ + || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) encrypt_des(magic, lmbuffer, pw); encrypt_des(magic, lmbuffer + 8, pw + 7); #endif @@ -505,7 +530,7 @@ static void ascii_uppercase_to_unicode_le(unsigned char *dest, * Set up nt hashed passwords * @unittest: 1600 */ -CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data, +CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data, const char *password, unsigned char *ntbuffer /* 21 bytes */) { @@ -541,8 +566,10 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data, gcry_md_hd_t MD4pw; gcry_md_open(&MD4pw, GCRY_MD_MD4, 0); gcry_md_write(MD4pw, pw, 2 * len); - memcpy (ntbuffer, gcry_md_read (MD4pw, 0), MD4_DIGEST_LENGTH); + memcpy(ntbuffer, gcry_md_read(MD4pw, 0), MD4_DIGEST_LENGTH); gcry_md_close(MD4pw); +#elif defined(USE_MBEDTLS) + mbedtls_md4(pw, 2 * len, ntbuffer); #elif defined(USE_NSS) || defined(USE_OS400CRYPTO) Curl_md4it(ntbuffer, pw, 2 * len); #elif defined(USE_DARWINSSL) @@ -688,8 +715,10 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash, /* Create the BLOB structure */ snprintf((char *)ptr + NTLM_HMAC_MD5_LEN, NTLMv2_BLOB_LEN, - NTLMv2_BLOB_SIGNATURE + "%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */ "%c%c%c%c", /* Reserved = 0 */ + NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1], + NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3], 0, 0, 0, 0); Curl_write64_le(tw, ptr + 24); diff --git a/contrib/curl/lib/curl_ntlm_core.h b/contrib/curl/lib/curl_ntlm_core.h index cf37dc81..c5f90e77 100644 --- a/contrib/curl/lib/curl_ntlm_core.h +++ b/contrib/curl/lib/curl_ntlm_core.h @@ -64,12 +64,12 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys, const unsigned char *plaintext, unsigned char *results); -CURLcode Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, +CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data, const char *password, unsigned char *lmbuffer /* 21 bytes */); #if USE_NTRESPONSES -CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data, +CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data, const char *password, unsigned char *ntbuffer /* 21 bytes */); diff --git a/contrib/curl/lib/curl_ntlm_wb.c b/contrib/curl/lib/curl_ntlm_wb.c index afdea16c..9f5b87bc 100644 --- a/contrib/curl/lib/curl_ntlm_wb.c +++ b/contrib/curl/lib/curl_ntlm_wb.c @@ -28,7 +28,7 @@ /* * NTLM details: * - * http://davenport.sourceforge.net/ntlm.html + * https://davenport.sourceforge.io/ntlm.html * https://www.innovation.ch/java/ntlm.html */ @@ -51,6 +51,7 @@ #include "curl_ntlm_wb.h" #include "url.h" #include "strerror.h" +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -156,7 +157,8 @@ static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp) } slash = strpbrk(username, "\\/"); if(slash) { - if((domain = strdup(username)) == NULL) + domain = strdup(username); + if(!domain) return CURLE_OUT_OF_MEMORY; slash = domain + (slash - username); *slash = '\0'; @@ -293,11 +295,10 @@ static CURLcode ntlm_wb_response(struct connectdata *conn, buf[len_out - 1] = '\0'; break; } - newbuf = realloc(buf, len_out + NTLM_BUFSIZE); - if(!newbuf) { - free(buf); + newbuf = Curl_saferealloc(buf, len_out + NTLM_BUFSIZE); + if(!newbuf) return CURLE_OUT_OF_MEMORY; - } + buf = newbuf; } @@ -349,7 +350,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, if(proxy) { allocuserpwd = &conn->allocptr.proxyuserpwd; - userp = conn->proxyuser; + userp = conn->http_proxy.user; ntlm = &conn->proxyntlm; authp = &conn->data->state.authproxy; } diff --git a/contrib/curl/lib/curl_sasl.c b/contrib/curl/lib/curl_sasl.c index 94b39e4a..807f5de7 100644 --- a/contrib/curl/lib/curl_sasl.c +++ b/contrib/curl/lib/curl_sasl.c @@ -42,8 +42,6 @@ #include "curl_sasl.h" #include "warnless.h" #include "strtok.h" -#include "strequal.h" -#include "rawstr.h" #include "sendf.h" #include "non-ascii.h" /* included for Curl_convert_... prototypes */ /* The last 3 #include files should be in this order */ @@ -159,7 +157,7 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl, sasl->prefmech = SASL_AUTH_NONE; } - if(strnequal(value, "*", len)) + if(!strncmp(value, "*", len)) sasl->prefmech = SASL_AUTH_DEFAULT; else { mechbit = Curl_sasl_decode_mech(value, len, &mechlen); @@ -257,17 +255,20 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, bool force_ir, saslprogress *progress) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; unsigned int enabledmechs; const char *mech = NULL; char *resp = NULL; size_t len = 0; saslstate state1 = SASL_STOP; saslstate state2 = SASL_FINAL; + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; + const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; #if defined(USE_KERBEROS5) - const char* service = data->set.str[STRING_SERVICE_NAME] ? - data->set.str[STRING_SERVICE_NAME] : - sasl->params->service; + const char *service = data->set.str[STRING_SERVICE_NAME] ? + data->set.str[STRING_SERVICE_NAME] : + sasl->params->service; #endif sasl->force_ir = force_ir; /* Latch for future use */ @@ -288,7 +289,8 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, } else if(conn->bits.user_passwd) { #if defined(USE_KERBEROS5) - if(enabledmechs & SASL_MECH_GSSAPI) { + if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() && + Curl_auth_user_contains_domain(conn->user)) { sasl->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */ mech = SASL_MECH_STRING_GSSAPI; state1 = SASL_GSSAPI; @@ -308,7 +310,8 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, else #endif #ifndef CURL_DISABLE_CRYPTO_AUTH - if(enabledmechs & SASL_MECH_DIGEST_MD5) { + if((enabledmechs & SASL_MECH_DIGEST_MD5) && + Curl_auth_is_digest_supported()) { mech = SASL_MECH_STRING_DIGEST_MD5; state1 = SASL_DIGESTMD5; sasl->authused = SASL_MECH_DIGEST_MD5; @@ -321,7 +324,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, else #endif #ifdef USE_NTLM - if(enabledmechs & SASL_MECH_NTLM) { + if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) { mech = SASL_MECH_STRING_NTLM; state1 = SASL_NTLM; state2 = SASL_NTLM_TYPE2MSG; @@ -341,8 +344,8 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn, if(force_ir || data->set.sasl_ir) result = Curl_auth_create_oauth_bearer_message(data, conn->user, - conn->host.name, - conn->port, + hostname, + port, conn->oauth_bearer, &resp, &len); } @@ -405,9 +408,12 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, int code, saslprogress *progress) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; saslstate newstate = SASL_FINAL; char *resp = NULL; + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; + const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; #if !defined(CURL_DISABLE_CRYPTO_AUTH) char *serverdata; char *chlg = NULL; @@ -542,8 +548,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn, /* Create the authorisation message */ if(sasl->authused == SASL_MECH_OAUTHBEARER) { result = Curl_auth_create_oauth_bearer_message(data, conn->user, - conn->host.name, - conn->port, + hostname, + port, conn->oauth_bearer, &resp, &len); diff --git a/contrib/curl/lib/curl_sasl.h b/contrib/curl/lib/curl_sasl.h index 6535fedb..7647a48b 100644 --- a/contrib/curl/lib/curl_sasl.h +++ b/contrib/curl/lib/curl_sasl.h @@ -24,7 +24,7 @@ #include -struct SessionHandle; +struct Curl_easy; struct connectdata; /* Authentication mechanism flags */ diff --git a/contrib/curl/lib/curl_sec.h b/contrib/curl/lib/curl_sec.h index 3f94e144..7bdde269 100644 --- a/contrib/curl/lib/curl_sec.h +++ b/contrib/curl/lib/curl_sec.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -30,8 +30,8 @@ struct Curl_sec_client_mech { void (*end)(void *); int (*check_prot)(void *, int); int (*overhead)(void *, int, int); - int (*encode)(void *, const void*, int, int, void**); - int (*decode)(void *, void*, int, int, struct connectdata *); + int (*encode)(void *, const void *, int, int, void **); + int (*decode)(void *, void *, int, int, struct connectdata *); }; #define AUTH_OK 0 @@ -39,11 +39,11 @@ struct Curl_sec_client_mech { #define AUTH_ERROR 2 #ifdef HAVE_GSSAPI -int Curl_sec_read_msg (struct connectdata *conn, char *, - enum protection_level); -void Curl_sec_end (struct connectdata *); -CURLcode Curl_sec_login (struct connectdata *); -int Curl_sec_request_prot (struct connectdata *conn, const char *level); +int Curl_sec_read_msg(struct connectdata *conn, char *, + enum protection_level); +void Curl_sec_end(struct connectdata *); +CURLcode Curl_sec_login(struct connectdata *); +int Curl_sec_request_prot(struct connectdata *conn, const char *level); extern struct Curl_sec_client_mech Curl_krb5_client_mech; #endif diff --git a/contrib/curl/lib/curl_setup.h b/contrib/curl/lib/curl_setup.h index 93a59ab2..e6e654cd 100644 --- a/contrib/curl/lib/curl_setup.h +++ b/contrib/curl/lib/curl_setup.h @@ -229,6 +229,15 @@ # include "setup-vms.h" #endif +/* + * Use getaddrinfo to resolve the IPv4 address literal. If the current network + * interface doesn’t support IPv4, but supports IPv6, NAT64, and DNS64, + * performing this task will result in a synthesized IPv6 address. + */ +#ifdef __APPLE__ +#define USE_RESOLVE_ON_IPS 1 +#endif + /* * Include header files for windows builds before redefining anything. * Use this preprocessor block only to include or exclude windows.h, @@ -466,8 +475,8 @@ # ifdef __minix /* Minix 3 versions up to at least 3.1.3 are missing these prototypes */ - extern char * strtok_r(char *s, const char *delim, char **last); - extern struct tm * gmtime_r(const time_t * const timep, struct tm *tmp); + extern char *strtok_r(char *s, const char *delim, char **last); + extern struct tm *gmtime_r(const time_t * const timep, struct tm *tmp); # endif # define DIR_CHAR "/" @@ -598,10 +607,9 @@ int netware_init(void); #endif #endif -#if defined(HAVE_LIBIDN) && defined(HAVE_TLD_H) -/* The lib was present and the tld.h header (which is missing in libidn 0.3.X - but we only work with libidn 0.4.1 or later) */ -#define USE_LIBIDN +#if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) +/* The lib and header are present */ +#define USE_LIBIDN2 #endif #ifndef SIZEOF_TIME_T @@ -637,6 +645,13 @@ int netware_init(void); defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) #define USE_NTLM + +#elif defined(USE_MBEDTLS) +# include +# if defined(MBEDTLS_MD4_C) +#define USE_NTLM +# endif + #endif #endif @@ -745,4 +760,14 @@ endings either CRLF or LF so 't' is appropriate. # endif #endif /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */ +/* Detect Windows App environment which has a restricted access + * to the Win32 APIs. */ +# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602) +# include +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \ + !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# define CURL_WINDOWS_APP +# endif +# endif + #endif /* HEADER_CURL_SETUP_H */ diff --git a/contrib/curl/lib/curl_sspi.c b/contrib/curl/lib/curl_sspi.c index 54bbef6f..11a7120a 100644 --- a/contrib/curl/lib/curl_sspi.c +++ b/contrib/curl/lib/curl_sspi.c @@ -64,10 +64,15 @@ PSecurityFunctionTable s_pSecFn = NULL; * * Once this function has been executed, Windows SSPI functions can be * called through the Security Service Provider Interface dispatch table. + * + * Parameters: + * + * None. + * + * Returns CURLE_OK on success. */ CURLcode Curl_sspi_global_init(void) { - bool securityDll = FALSE; INITSECURITYINTERFACE_FN pInitSecurityInterface; /* If security interface is not yet initialized try to do this */ @@ -75,49 +80,9 @@ CURLcode Curl_sspi_global_init(void) /* Security Service Provider Interface (SSPI) functions are located in * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP * have both these DLLs (security.dll forwards calls to secur32.dll) */ - DWORD majorVersion = 4; - DWORD platformId = VER_PLATFORM_WIN32_NT; - -#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ - (_WIN32_WINNT < _WIN32_WINNT_WIN2K) - OSVERSIONINFO osver; - - memset(&osver, 0, sizeof(osver)); - osver.dwOSVersionInfoSize = sizeof(osver); - - /* Find out Windows version */ - if(!GetVersionEx(&osver)) - return CURLE_FAILED_INIT; - - /* Verify the major version number == 4 and platform id == WIN_NT */ - if(osver.dwMajorVersion == majorVersion && - osver.dwPlatformId == platformId) - securityDll = TRUE; -#else - ULONGLONG cm; - OSVERSIONINFOEX osver; - - memset(&osver, 0, sizeof(osver)); - osver.dwOSVersionInfoSize = sizeof(osver); - osver.dwMajorVersion = majorVersion; - osver.dwPlatformId = platformId; - - cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL); - cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_GREATER_EQUAL); - cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); - cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); - cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL); - - /* Verify the major version number == 4 and platform id == WIN_NT */ - if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION | - VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR | - VER_PLATFORMID), - cm)) - securityDll = TRUE; -#endif /* Load SSPI dll into the address space of the calling process */ - if(securityDll) + if(Curl_verify_windows_version(4, 0, PLATFORM_WINNT, VERSION_EQUAL)) s_hSecDll = Curl_load_library(TEXT("security.dll")); else s_hSecDll = Curl_load_library(TEXT("secur32.dll")); @@ -143,8 +108,11 @@ CURLcode Curl_sspi_global_init(void) * Curl_sspi_global_cleanup() * * This deinitializes the Security Service Provider Interface from libcurl. + * + * Parameters: + * + * None. */ - void Curl_sspi_global_cleanup(void) { if(s_hSecDll) { @@ -246,6 +214,15 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, return CURLE_OK; } +/* + * Curl_sspi_free_identity() + * + * This is used to free the contents of a SSPI identifier structure. + * + * Parameters: + * + * identity [in/out] - The identity structure. + */ void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity) { if(identity) { diff --git a/contrib/curl/lib/curl_threads.c b/contrib/curl/lib/curl_threads.c index c98d8bba..a78eff5c 100644 --- a/contrib/curl/lib/curl_threads.c +++ b/contrib/curl/lib/curl_threads.c @@ -59,7 +59,7 @@ static void *curl_thread_create_thunk(void *arg) return 0; } -curl_thread_t Curl_thread_create(unsigned int (*func) (void*), void *arg) +curl_thread_t Curl_thread_create(unsigned int (*func) (void *), void *arg) { curl_thread_t t = malloc(sizeof(pthread_t)); struct curl_actual_call *ac = malloc(sizeof(struct curl_actual_call)); @@ -100,7 +100,8 @@ int Curl_thread_join(curl_thread_t *hnd) #elif defined(USE_THREADS_WIN32) -curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void*), +/* !checksrc! disable SPACEBEFOREPAREN 1 */ +curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *), void *arg) { #ifdef _WIN32_WCE diff --git a/contrib/curl/lib/curl_threads.h b/contrib/curl/lib/curl_threads.h index 8cbac63a..9e0d14a3 100644 --- a/contrib/curl/lib/curl_threads.h +++ b/contrib/curl/lib/curl_threads.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -50,7 +50,8 @@ #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) -curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void*), +/* !checksrc! disable SPACEBEFOREPAREN 1 */ +curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *), void *arg); void Curl_thread_destroy(curl_thread_t hnd); diff --git a/contrib/curl/lib/curlx.h b/contrib/curl/lib/curlx.h index 448a34ff..6168dc11 100644 --- a/contrib/curl/lib/curlx.h +++ b/contrib/curl/lib/curlx.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -34,8 +34,8 @@ functions while they still are offered publicly. They will be made library- private one day */ -#include "strequal.h" -/* "strequal.h" provides the strequal protos */ +#include "strcase.h" +/* "strcase.h" provides the strcasecompare protos */ #include "strtoofft.h" /* "strtoofft.h" provides this function: curlx_strtoofft(), returns a @@ -67,15 +67,12 @@ be removed from a future libcurl official API: curlx_getenv curlx_mprintf (and its variations) - curlx_strequal - curlx_strnequal + curlx_strcasecompare + curlx_strncasecompare */ #define curlx_getenv curl_getenv -#define curlx_strequal curl_strequal -#define curlx_strnequal curl_strnequal -#define curlx_raw_equal Curl_raw_equal #define curlx_mvsnprintf curl_mvsnprintf #define curlx_msnprintf curl_msnprintf #define curlx_maprintf curl_maprintf diff --git a/contrib/curl/lib/dict.c b/contrib/curl/lib/dict.c index 2e7cb477..69defc4c 100644 --- a/contrib/curl/lib/dict.c +++ b/contrib/curl/lib/dict.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -52,11 +52,10 @@ #include #include "transfer.h" #include "sendf.h" - +#include "escape.h" #include "progress.h" -#include "strequal.h" #include "dict.h" -#include "rawstr.h" +#include "strcase.h" #include "curl_memory.h" /* The last #include file should be: */ #include "memdebug.h" @@ -91,17 +90,17 @@ const struct Curl_handler Curl_handler_dict = { PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */ }; -static char *unescape_word(struct SessionHandle *data, const char *inputbuff) +static char *unescape_word(struct Curl_easy *data, const char *inputbuff) { char *newp; char *dictp; char *ptr; - int len; + size_t len; char ch; int olen=0; - newp = curl_easy_unescape(data, inputbuff, 0, &len); - if(!newp) + CURLcode result = Curl_urldecode(data, inputbuff, 0, &newp, &len, FALSE); + if(!newp || result) return NULL; dictp = malloc(((size_t)len)*2 + 1); /* add one for terminating zero */ @@ -133,7 +132,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done) char *nthdef = NULL; /* This is not part of the protocol, but required by RFC 2229 */ CURLcode result=CURLE_OK; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; char *path = data->state.path; @@ -145,9 +144,9 @@ static CURLcode dict_do(struct connectdata *conn, bool *done) /* AUTH is missing */ } - if(Curl_raw_nequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) || - Curl_raw_nequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) || - Curl_raw_nequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) { + if(strncasecompare(path, DICT_MATCH, sizeof(DICT_MATCH)-1) || + strncasecompare(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) || + strncasecompare(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) { word = strchr(path, ':'); if(word) { @@ -203,9 +202,9 @@ static CURLcode dict_do(struct connectdata *conn, bool *done) Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, -1, NULL); /* no upload */ } - else if(Curl_raw_nequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || - Curl_raw_nequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || - Curl_raw_nequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) { + else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || + strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || + strncasecompare(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) { word = strchr(path, ':'); if(word) { diff --git a/contrib/curl/lib/easy.c b/contrib/curl/lib/easy.c index ea7af5e5..bed94a44 100644 --- a/contrib/curl/lib/easy.c +++ b/contrib/curl/lib/easy.c @@ -50,7 +50,6 @@ #include #endif -#include "strequal.h" #include "urldata.h" #include #include "transfer.h" @@ -144,28 +143,6 @@ static CURLcode win32_init(void) return CURLE_OK; } -#ifdef USE_LIBIDN -/* - * Initialise use of IDNA library. - * It falls back to ASCII if $CHARSET isn't defined. This doesn't work for - * idna_to_ascii_lz(). - */ -static void idna_init (void) -{ -#ifdef WIN32 - char buf[60]; - UINT cp = GetACP(); - - if(!getenv("CHARSET") && cp > 0) { - snprintf(buf, sizeof(buf), "CHARSET=cp%u", cp); - putenv(buf); - } -#else - /* to do? */ -#endif -} -#endif /* USE_LIBIDN */ - /* true globals -- for curl_global_init() and curl_global_cleanup() */ static unsigned int initialized; static long init_flags; @@ -217,7 +194,7 @@ curl_calloc_callback Curl_ccalloc; #endif /** - * curl_global_init() globally initializes cURL given a bitwise set of the + * curl_global_init() globally initializes curl given a bitwise set of the * different features of what to initialize. */ static CURLcode global_init(long flags, bool memoryfuncs) @@ -262,15 +239,13 @@ static CURLcode global_init(long flags, bool memoryfuncs) } #endif -#ifdef USE_LIBIDN - idna_init(); -#endif - if(Curl_resolver_global_init()) { DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n")); return CURLE_FAILED_INIT; } + (void)Curl_ipv6works(); + #if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_INIT) if(libssh2_init(0)) { DEBUGF(fprintf(stderr, "Error: libssh2_init failed\n")); @@ -290,7 +265,7 @@ static CURLcode global_init(long flags, bool memoryfuncs) /** - * curl_global_init() globally initializes cURL given a bitwise set of the + * curl_global_init() globally initializes curl given a bitwise set of the * different features of what to initialize. */ CURLcode curl_global_init(long flags) @@ -299,7 +274,7 @@ CURLcode curl_global_init(long flags) } /* - * curl_global_init_mem() globally initializes cURL and also registers the + * curl_global_init_mem() globally initializes curl and also registers the * user provided callback routines. */ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, @@ -331,7 +306,7 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m, } /** - * curl_global_cleanup() globally cleanups cURL, uses the value of + * curl_global_cleanup() globally cleanups curl, uses the value of * "init_flags" to determine what needs to be cleaned up and what doesn't. */ void curl_global_cleanup(void) @@ -365,10 +340,10 @@ void curl_global_cleanup(void) * curl_easy_init() is the external interface to alloc, setup and init an * easy handle that is returned. If anything goes wrong, NULL is returned. */ -CURL *curl_easy_init(void) +struct Curl_easy *curl_easy_init(void) { CURLcode result; - struct SessionHandle *data; + struct Curl_easy *data; /* Make sure we inited the global SSL stuff */ if(!initialized) { @@ -396,13 +371,12 @@ CURL *curl_easy_init(void) */ #undef curl_easy_setopt -CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...) +CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...) { va_list arg; - struct SessionHandle *data = curl; CURLcode result; - if(!curl) + if(!data) return CURLE_BAD_FUNCTION_ARGUMENT; va_start(arg, tag); @@ -434,7 +408,7 @@ struct events { * updated. */ -static int events_timer(CURLM *multi, /* multi handle */ +static int events_timer(struct Curl_multi *multi, /* multi handle */ long timeout_ms, /* see above */ void *userp) /* private callback pointer */ { @@ -489,7 +463,7 @@ static short socketcb2poll(int pollmask) * Callback that gets called with information about socket activity to * monitor. */ -static int events_socket(CURL *easy, /* easy handle */ +static int events_socket(struct Curl_easy *easy, /* easy handle */ curl_socket_t s, /* socket */ int what, /* see above */ void *userp, /* private callback @@ -567,7 +541,7 @@ static int events_socket(CURL *easy, /* easy handle */ * * Do the multi handle setups that only event-based transfers need. */ -static void events_setup(CURLM *multi, struct events *ev) +static void events_setup(struct Curl_multi *multi, struct events *ev) { /* timer callback */ curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer); @@ -671,7 +645,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) * * Runs a transfer in a blocking manner using the events-based API */ -static CURLcode easy_events(CURLM *multi) +static CURLcode easy_events(struct Curl_multi *multi) { struct events evs= {2, FALSE, 0, NULL, 0}; @@ -685,7 +659,7 @@ static CURLcode easy_events(CURLM *multi) #define easy_events(x) CURLE_NOT_BUILT_IN #endif -static CURLcode easy_transfer(CURLM *multi) +static CURLcode easy_transfer(struct Curl_multi *multi) { bool done = FALSE; CURLMcode mcode = CURLM_OK; @@ -765,9 +739,9 @@ static CURLcode easy_transfer(CURLM *multi) * DEBUG: if 'events' is set TRUE, this function will use a replacement engine * instead of curl_multi_perform() and use curl_multi_socket_action(). */ -static CURLcode easy_perform(struct SessionHandle *data, bool events) +static CURLcode easy_perform(struct Curl_easy *data, bool events) { - CURLM *multi; + struct Curl_multi *multi; CURLMcode mcode; CURLcode result = CURLE_OK; SIGPIPE_VARIABLE(pipe_st); @@ -827,9 +801,9 @@ static CURLcode easy_perform(struct SessionHandle *data, bool events) * curl_easy_perform() is the external interface that performs a blocking * transfer as previously setup. */ -CURLcode curl_easy_perform(CURL *easy) +CURLcode curl_easy_perform(struct Curl_easy *data) { - return easy_perform(easy, FALSE); + return easy_perform(data, FALSE); } #ifdef CURLDEBUG @@ -837,9 +811,9 @@ CURLcode curl_easy_perform(CURL *easy) * curl_easy_perform_ev() is the external interface that performs a blocking * transfer using the event-based API internally. */ -CURLcode curl_easy_perform_ev(CURL *easy) +CURLcode curl_easy_perform_ev(struct Curl_easy *data) { - return easy_perform(easy, TRUE); + return easy_perform(data, TRUE); } #endif @@ -848,9 +822,8 @@ CURLcode curl_easy_perform_ev(CURL *easy) * curl_easy_cleanup() is the external interface to cleaning/freeing the given * easy handle. */ -void curl_easy_cleanup(CURL *curl) +void curl_easy_cleanup(struct Curl_easy *data) { - struct SessionHandle *data = (struct SessionHandle *)curl; SIGPIPE_VARIABLE(pipe_st); if(!data) @@ -866,12 +839,11 @@ void curl_easy_cleanup(CURL *curl) * information from a performed transfer and similar. */ #undef curl_easy_getinfo -CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...) +CURLcode curl_easy_getinfo(struct Curl_easy *data, CURLINFO info, ...) { va_list arg; void *paramp; CURLcode result; - struct SessionHandle *data = (struct SessionHandle *)curl; va_start(arg, info); paramp = va_arg(arg, void *); @@ -887,11 +859,9 @@ CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...) * given input easy handle. The returned handle will be a new working handle * with all options set exactly as the input source handle. */ -CURL *curl_easy_duphandle(CURL *incurl) +struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data) { - struct SessionHandle *data=(struct SessionHandle *)incurl; - - struct SessionHandle *outcurl = calloc(1, sizeof(struct SessionHandle)); + struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy)); if(NULL == outcurl) goto fail; @@ -900,6 +870,11 @@ CURL *curl_easy_duphandle(CURL *incurl) * get setup on-demand in the code, as that would probably decrease * the likeliness of us forgetting to init a buffer here in the future. */ + outcurl->set.buffer_size = data->set.buffer_size; + outcurl->state.buffer = malloc(CURL_BUFSIZE(outcurl->set.buffer_size) + 1); + if(!outcurl->state.buffer) + goto fail; + outcurl->state.headerbuff = malloc(HEADERSIZE); if(!outcurl->state.headerbuff) goto fail; @@ -957,6 +932,8 @@ CURL *curl_easy_duphandle(CURL *incurl) Curl_convert_setup(outcurl); + Curl_initinfo(outcurl); + outcurl->magic = CURLEASY_MAGIC_NUMBER; /* we reach this point and thus we are OK */ @@ -968,6 +945,7 @@ CURL *curl_easy_duphandle(CURL *incurl) if(outcurl) { curl_slist_free_all(outcurl->change.cookielist); outcurl->change.cookielist = NULL; + Curl_safefree(outcurl->state.buffer); Curl_safefree(outcurl->state.headerbuff); Curl_safefree(outcurl->change.url); Curl_safefree(outcurl->change.referer); @@ -982,10 +960,8 @@ CURL *curl_easy_duphandle(CURL *incurl) * curl_easy_reset() is an external interface that allows an app to re- * initialize a session handle to the default values. */ -void curl_easy_reset(CURL *curl) +void curl_easy_reset(struct Curl_easy *data) { - struct SessionHandle *data = (struct SessionHandle *)curl; - Curl_safefree(data->state.pathbuffer); data->state.path = NULL; @@ -1000,6 +976,9 @@ void curl_easy_reset(CURL *curl) /* zero out Progress data: */ memset(&data->progress, 0, sizeof(struct Progress)); + /* zero out PureInfo data: */ + Curl_initinfo(data); + data->progress.flags |= PGRS_HIDE; data->state.current_speed = -1; /* init to negative == impossible */ } @@ -1014,9 +993,8 @@ void curl_easy_reset(CURL *curl) * * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h */ -CURLcode curl_easy_pause(CURL *curl, int action) +CURLcode curl_easy_pause(struct Curl_easy *data, int action) { - struct SessionHandle *data = (struct SessionHandle *)curl; struct SingleRequest *k = &data->req; CURLcode result = CURLE_OK; @@ -1050,13 +1028,13 @@ CURLcode curl_easy_pause(CURL *curl, int action) if(!result && ((newstate&(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) != (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) ) - Curl_expire(data, 1); /* get this handle going again */ + Curl_expire(data, 0); /* get this handle going again */ return result; } -static CURLcode easy_connection(struct SessionHandle *data, +static CURLcode easy_connection(struct Curl_easy *data, curl_socket_t *sfd, struct connectdata **connp) { @@ -1084,13 +1062,13 @@ static CURLcode easy_connection(struct SessionHandle *data, * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. * Returns CURLE_OK on success, error code on error. */ -CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n) +CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen, + size_t *n) { curl_socket_t sfd; CURLcode result; ssize_t n1; struct connectdata *c; - struct SessionHandle *data = (struct SessionHandle *)curl; result = easy_connection(data, &sfd, &c); if(result) @@ -1111,14 +1089,13 @@ CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n) * Sends data over the connected socket. Use after successful * curl_easy_perform() with CURLOPT_CONNECT_ONLY option. */ -CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen, - size_t *n) +CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer, + size_t buflen, size_t *n) { curl_socket_t sfd; CURLcode result; ssize_t n1; struct connectdata *c = NULL; - struct SessionHandle *data = (struct SessionHandle *)curl; result = easy_connection(data, &sfd, &c); if(result) diff --git a/contrib/curl/lib/easyif.h b/contrib/curl/lib/easyif.h index 65333494..f6132cc7 100644 --- a/contrib/curl/lib/easyif.h +++ b/contrib/curl/lib/easyif.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,7 +26,7 @@ * Prototypes for library-wide functions provided by easy.c */ #ifdef CURLDEBUG -CURL_EXTERN CURLcode curl_easy_perform_ev(CURL *easy); +CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy); #endif #endif /* HEADER_CURL_EASYIF_H */ diff --git a/contrib/curl/lib/escape.c b/contrib/curl/lib/escape.c index 2c6a7f65..9c811b8e 100644 --- a/contrib/curl/lib/escape.c +++ b/contrib/curl/lib/escape.c @@ -31,6 +31,7 @@ #include "warnless.h" #include "non-ascii.h" #include "escape.h" +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -42,7 +43,7 @@ */ static bool Curl_isunreserved(unsigned char in) { - switch (in) { + switch(in) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'a': case 'b': case 'c': case 'd': case 'e': @@ -75,17 +76,24 @@ char *curl_unescape(const char *string, int length) return curl_easy_unescape(NULL, string, length, NULL); } -char *curl_easy_escape(CURL *handle, const char *string, int inlength) +char *curl_easy_escape(struct Curl_easy *data, const char *string, + int inlength) { - size_t alloc = (inlength?(size_t)inlength:strlen(string))+1; + size_t alloc; char *ns; char *testing_ptr = NULL; unsigned char in; /* we need to treat the characters unsigned */ - size_t newlen = alloc; + size_t newlen; size_t strindex=0; size_t length; CURLcode result; + if(inlength < 0) + return NULL; + + alloc = (inlength?(size_t)inlength:strlen(string))+1; + newlen = alloc; + ns = malloc(alloc); if(!ns) return NULL; @@ -102,17 +110,15 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength) newlen += 2; /* the size grows with two, since this'll become a %XX */ if(newlen > alloc) { alloc *= 2; - testing_ptr = realloc(ns, alloc); - if(!testing_ptr) { - free(ns); + testing_ptr = Curl_saferealloc(ns, alloc); + if(!testing_ptr) return NULL; - } else { ns = testing_ptr; } } - result = Curl_convert_to_network(handle, &in, 1); + result = Curl_convert_to_network(data, &in, 1); if(result) { /* Curl_convert_to_network calls failf if unsuccessful */ free(ns); @@ -139,7 +145,7 @@ char *curl_easy_escape(CURL *handle, const char *string, int inlength) * *olen. If length == 0, the length is assumed to be strlen(string). * */ -CURLcode Curl_urldecode(struct SessionHandle *data, +CURLcode Curl_urldecode(struct Curl_easy *data, const char *string, size_t length, char **ostring, size_t *olen, bool reject_ctrl) @@ -206,18 +212,26 @@ CURLcode Curl_urldecode(struct SessionHandle *data, * If length == 0, the length is assumed to be strlen(string). * If olen == NULL, no output length is stored. */ -char *curl_easy_unescape(CURL *handle, const char *string, int length, - int *olen) +char *curl_easy_unescape(struct Curl_easy *data, const char *string, + int length, int *olen) { char *str = NULL; - size_t inputlen = length; - size_t outputlen; - CURLcode res = Curl_urldecode(handle, string, inputlen, &str, &outputlen, - FALSE); - if(res) - return NULL; - if(olen) - *olen = curlx_uztosi(outputlen); + if(length >= 0) { + size_t inputlen = length; + size_t outputlen; + CURLcode res = Curl_urldecode(data, string, inputlen, &str, &outputlen, + FALSE); + if(res) + return NULL; + + if(olen) { + if(outputlen <= (size_t) INT_MAX) + *olen = curlx_uztosi(outputlen); + else + /* too large to return in an int, fail! */ + Curl_safefree(str); + } + } return str; } diff --git a/contrib/curl/lib/escape.h b/contrib/curl/lib/escape.h index a6e2967b..638666f0 100644 --- a/contrib/curl/lib/escape.h +++ b/contrib/curl/lib/escape.h @@ -24,7 +24,7 @@ /* Escape and unescape URL encoding in strings. The functions return a new * allocated string or NULL if an error occurred. */ -CURLcode Curl_urldecode(struct SessionHandle *data, +CURLcode Curl_urldecode(struct Curl_easy *data, const char *string, size_t length, char **ostring, size_t *olen, bool reject_crlf); diff --git a/contrib/curl/lib/file.c b/contrib/curl/lib/file.c index 1eeb84d5..e90902c5 100644 --- a/contrib/curl/lib/file.c +++ b/contrib/curl/lib/file.c @@ -135,7 +135,7 @@ static CURLcode file_range(struct connectdata *conn) curl_off_t totalsize=-1; char *ptr; char *ptr2; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(data->state.use_range && data->state.range) { from=curlx_strtoofft(data->state.range, &ptr, 0); @@ -185,19 +185,20 @@ static CURLcode file_range(struct connectdata *conn) */ static CURLcode file_connect(struct connectdata *conn, bool *done) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char *real_path; struct FILEPROTO *file = data->req.protop; int fd; #ifdef DOS_FILESYSTEM - int i; + size_t i; char *actual_path; #endif - int real_path_len; + size_t real_path_len; - real_path = curl_easy_unescape(data, data->state.path, 0, &real_path_len); - if(!real_path) - return CURLE_OUT_OF_MEMORY; + CURLcode result = Curl_urldecode(data, data->state.path, 0, &real_path, + &real_path_len, FALSE); + if(result) + return result; #ifdef DOS_FILESYSTEM /* If the first character is a slash, and there's @@ -227,15 +228,19 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) for(i=0; i < real_path_len; ++i) if(actual_path[i] == '/') actual_path[i] = '\\'; - else if(!actual_path[i]) /* binary zero */ + else if(!actual_path[i]) { /* binary zero */ + Curl_safefree(real_path); return CURLE_URL_MALFORMAT; + } fd = open_readonly(actual_path, O_RDONLY|O_BINARY); file->path = actual_path; #else - if(memchr(real_path, 0, real_path_len)) + if(memchr(real_path, 0, real_path_len)) { /* binary zeroes indicate foul play */ + Curl_safefree(real_path); return CURLE_URL_MALFORMAT; + } fd = open_readonly(real_path, O_RDONLY); file->path = real_path; @@ -301,14 +306,14 @@ static CURLcode file_upload(struct connectdata *conn) int fd; int mode; CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char *buf = data->state.buffer; size_t nread; size_t nwrite; curl_off_t bytecount = 0; struct timeval now = Curl_tvnow(); struct_stat file_stat; - const char* buf2; + const char *buf2; /* * Since FILE: doesn't do the full init, we need to provide some extra @@ -428,7 +433,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done) bool size_known; bool fstated=FALSE; ssize_t nread; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char *buf = data->state.buffer; curl_off_t bytecount = 0; int fd; @@ -471,7 +476,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done) time_t filetime; struct tm buffer; const struct tm *tm = &buffer; - snprintf(buf, sizeof(data->state.buffer), + snprintf(buf, CURL_BUFSIZE(data->set.buffer_size), "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", expected_size); result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); if(result) diff --git a/contrib/curl/lib/formdata.c b/contrib/curl/lib/formdata.c index a71f099c..c214ba28 100644 --- a/contrib/curl/lib/formdata.c +++ b/contrib/curl/lib/formdata.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -30,12 +30,13 @@ #include #endif -#include "urldata.h" /* for struct SessionHandle */ +#include "urldata.h" /* for struct Curl_easy */ #include "formdata.h" #include "vtls/vtls.h" -#include "strequal.h" +#include "strcase.h" #include "sendf.h" #include "strdup.h" +#include "rand.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -47,7 +48,7 @@ static char *Curl_basename(char *path); #endif static size_t readfromfile(struct Form *form, char *buffer, size_t size); -static char *formboundary(struct SessionHandle *data); +static char *formboundary(struct Curl_easy *data); /* What kind of Content-Type to use on un-specified files with unrecognized extensions. */ @@ -80,7 +81,7 @@ AddHttpPost(char *name, size_t namelength, char *buffer, size_t bufferlength, char *contenttype, long flags, - struct curl_slist* contentHeader, + struct curl_slist *contentHeader, char *showfilename, char *userp, struct curl_httppost *parent_post, struct curl_httppost **httppost, @@ -201,9 +202,9 @@ static const char *ContentTypeForFilename(const char *filename, if(filename) { /* in case a NULL was passed in */ for(i=0; i= strlen(ctts[i].extension)) { - if(strequal(filename + - strlen(filename) - strlen(ctts[i].extension), - ctts[i].extension)) { + if(strcasecompare(filename + + strlen(filename) - strlen(ctts[i].extension), + ctts[i].extension)) { contenttype = ctts[i].type; break; } @@ -315,7 +316,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, break; } - switch (option) { + switch(option) { case CURLFORM_ARRAY: if(array_state) /* we don't support an array from within an array */ @@ -547,9 +548,9 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, { /* this "cast increases required alignment of target type" but we consider it OK anyway */ - struct curl_slist* list = array_state? - (struct curl_slist*)(void*)array_value: - va_arg(params, struct curl_slist*); + struct curl_slist *list = array_state? + (struct curl_slist *)(void *)array_value: + va_arg(params, struct curl_slist *); if(current_form->contentheader) return_value = CURL_FORMADD_OPTION_TWICE; @@ -761,8 +762,8 @@ CURLFORMcode curl_formadd(struct curl_httppost **httppost, * and CD/DVD images should be either a STREAM_LF format or a fixed format. * */ -curl_off_t VmsRealFileSize(const char * name, - const struct_stat * stat_buf) +curl_off_t VmsRealFileSize(const char *name, + const struct_stat *stat_buf) { char buffer[8192]; curl_off_t count; @@ -791,8 +792,8 @@ curl_off_t VmsRealFileSize(const char * name, * if not to call a routine to get the correct size. * */ -static curl_off_t VmsSpecialSize(const char * name, - const struct_stat * stat_buf) +static curl_off_t VmsSpecialSize(const char *name, + const struct_stat *stat_buf) { switch(stat_buf->st_fab_rfm) { case FAB$C_VAR: @@ -845,16 +846,23 @@ static CURLcode AddFormData(struct FormData **formp, goto error; } #endif + if(type != FORM_DATAMEM) { + newform->line = malloc((size_t)length+1); + if(!newform->line) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + alloc2 = newform->line; + memcpy(newform->line, line, (size_t)length); - newform->line = malloc((size_t)length+1); - if(!newform->line) { - result = CURLE_OUT_OF_MEMORY; - goto error; + /* zero terminate for easier debugging */ + newform->line[(size_t)length]=0; + } + else { + newform->line = (char *)line; + type = FORM_DATA; /* in all other aspects this is just FORM_DATA */ } - alloc2 = newform->line; - memcpy(newform->line, line, (size_t)length); newform->length = (size_t)length; - newform->line[(size_t)length]=0; /* zero terminate for easier debugging */ } else /* For callbacks and files we don't have any actual data so we just keep a @@ -863,13 +871,6 @@ static CURLcode AddFormData(struct FormData **formp, newform->type = type; - if(*formp) { - (*formp)->next = newform; - *formp = newform; - } - else - *formp = newform; - if(size) { if(type != FORM_FILE) /* for static content as well as callback data we add the size given @@ -878,7 +879,7 @@ static CURLcode AddFormData(struct FormData **formp, else { /* Since this is a file to be uploaded here, add the size of the actual file */ - if(!strequal("-", newform->line)) { + if(strcmp("-", newform->line)) { struct_stat file; if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode)) *size += filesize(newform->line, file); @@ -889,6 +890,14 @@ static CURLcode AddFormData(struct FormData **formp, } } } + + if(*formp) { + (*formp)->next = newform; + *formp = newform; + } + else + *formp = newform; + return CURLE_OK; error: if(newform) @@ -906,13 +915,21 @@ static CURLcode AddFormDataf(struct FormData **formp, curl_off_t *size, const char *fmt, ...) { - char s[4096]; + char *s; + CURLcode result; va_list ap; va_start(ap, fmt); - vsnprintf(s, sizeof(s), fmt, ap); + s = curl_mvaprintf(fmt, ap); va_end(ap); - return AddFormData(formp, FORM_DATA, s, 0, size); + if(!s) + return CURLE_OUT_OF_MEMORY; + + result = AddFormData(formp, FORM_DATAMEM, s, 0, size); + if(result) + free(s); + + return result; } /* @@ -932,8 +949,8 @@ void Curl_formclean(struct FormData **form_ptr) if(form->type <= FORM_CONTENT) free(form->line); /* free the line */ free(form); /* free the struct */ - - } while((form = next) != NULL); /* continue */ + form = next; + } while(form); /* continue */ *form_ptr = NULL; } @@ -1014,8 +1031,8 @@ void curl_formfree(struct curl_httppost *form) free(form->contenttype); /* free the content type */ free(form->showfilename); /* free the faked file name */ free(form); /* free the struct */ - - } while((form = next) != NULL); /* continue */ + form = next; + } while(form); /* continue */ } #ifndef HAVE_BASENAME @@ -1136,7 +1153,7 @@ static CURLcode formdata_add_filename(const struct curl_httppost *file, * a NULL pointer in the 'data' argument. */ -CURLcode Curl_getformdata(struct SessionHandle *data, +CURLcode Curl_getformdata(struct Curl_easy *data, struct FormData **finalform, struct curl_httppost *post, const char *custom_content_type, @@ -1150,7 +1167,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data, curl_off_t size = 0; /* support potentially ENORMOUS formposts */ char *boundary; char *fileboundary = NULL; - struct curl_slist* curList; + struct curl_slist *curList; *finalform = NULL; /* default form is empty */ @@ -1289,7 +1306,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data, /* we should include the contents from the specified file */ FILE *fileread; - fileread = strequal("-", file->contents)? + fileread = !strcmp("-", file->contents)? stdin:fopen(file->contents, "rb"); /* binary read for win32 */ /* @@ -1315,7 +1332,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data, char buffer[512]; while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) { result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size); - if(result) + if(result || feof(fileread) || ferror(fileread)) break; } } @@ -1357,8 +1374,8 @@ CURLcode Curl_getformdata(struct SessionHandle *data, if(result) break; } - - } while((post = post->next) != NULL); /* for each field */ + post = post->next; + } while(post); /* for each field */ /* end-boundary for everything */ if(!result) @@ -1410,13 +1427,14 @@ int Curl_FormInit(struct Form *form, struct FormData *formdata) * */ # define fopen_read vmsfopenread -static FILE * vmsfopenread(const char *file, const char *mode) { +static FILE * vmsfopenread(const char *file, const char *mode) +{ struct_stat statbuf; int result; result = stat(file, &statbuf); - switch (statbuf.st_fab_rfm) { + switch(statbuf.st_fab_rfm) { case FAB$C_VAR: case FAB$C_VFC: case FAB$C_STMCR: @@ -1535,7 +1553,7 @@ char *Curl_formpostheader(void *formp, size_t *len) struct Form *form=(struct Form *)formp; if(!form->data) - return 0; /* nothing, ERROR! */ + return NULL; /* nothing, ERROR! */ header = form->data->line; *len = form->data->length; @@ -1549,12 +1567,16 @@ char *Curl_formpostheader(void *formp, size_t *len) * formboundary() creates a suitable boundary string and returns an allocated * one. */ -static char *formboundary(struct SessionHandle *data) +static char *formboundary(struct Curl_easy *data) { /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615) combinations */ - return aprintf("------------------------%08x%08x", - Curl_rand(data), Curl_rand(data)); + unsigned int rnd[2]; + CURLcode result = Curl_rand(data, &rnd[0], 2); + if(result) + return NULL; + + return aprintf("------------------------%08x%08x", rnd[0], rnd[1]); } #else /* CURL_DISABLE_HTTP */ diff --git a/contrib/curl/lib/formdata.h b/contrib/curl/lib/formdata.h index a5ebc1d4..69629f62 100644 --- a/contrib/curl/lib/formdata.h +++ b/contrib/curl/lib/formdata.h @@ -23,6 +23,7 @@ ***************************************************************************/ enum formtype { + FORM_DATAMEM, /* already allocated FORM_DATA memory */ FORM_DATA, /* form metadata (convert to network encoding if necessary) */ FORM_CONTENT, /* form content (never convert) */ FORM_CALLBACK, /* 'line' points to the custom pointer we pass to the callback @@ -64,13 +65,13 @@ typedef struct FormInfo { file name will be used */ bool showfilename_alloc; char *userp; /* pointer for the read callback */ - struct curl_slist* contentheader; + struct curl_slist *contentheader; struct FormInfo *more; } FormInfo; int Curl_FormInit(struct Form *form, struct FormData *formdata); -CURLcode Curl_getformdata(struct SessionHandle *data, +CURLcode Curl_getformdata(struct Curl_easy *data, struct FormData **, struct curl_httppost *post, const char *custom_contenttype, @@ -93,6 +94,6 @@ char *Curl_FormBoundary(void); void Curl_formclean(struct FormData **); -CURLcode Curl_formconvert(struct SessionHandle *, struct FormData *); +CURLcode Curl_formconvert(struct Curl_easy *, struct FormData *); #endif /* HEADER_CURL_FORMDATA_H */ diff --git a/contrib/curl/lib/ftp.c b/contrib/curl/lib/ftp.c index cfa1bbb8..aa4d5ac2 100644 --- a/contrib/curl/lib/ftp.c +++ b/contrib/curl/lib/ftp.c @@ -61,7 +61,7 @@ #include "ftplistparser.h" #include "curl_sec.h" #include "strtoofft.h" -#include "strequal.h" +#include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" @@ -72,7 +72,7 @@ #include "sockaddr.h" /* required for Curl_sockaddr_storage */ #include "multiif.h" #include "url.h" -#include "rawstr.h" +#include "strcase.h" #include "speedcheck.h" #include "warnless.h" #include "http_proxy.h" @@ -327,7 +327,7 @@ static bool isBadFtpString(const char *string) */ static CURLcode AcceptServerConnect(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_socket_t sock = conn->sock[SECONDARYSOCKET]; curl_socket_t s = CURL_SOCKET_BAD; #ifdef ENABLE_IPV6 @@ -384,10 +384,10 @@ static CURLcode AcceptServerConnect(struct connectdata *conn) * Curl_pgrsTime(..., TIMER_STARTACCEPT); * */ -static long ftp_timeleft_accept(struct SessionHandle *data) +static time_t ftp_timeleft_accept(struct Curl_easy *data) { - long timeout_ms = DEFAULT_ACCEPT_TIMEOUT; - long other; + time_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT; + time_t other; struct timeval now; if(data->set.accepttimeout > 0) @@ -424,13 +424,13 @@ static long ftp_timeleft_accept(struct SessionHandle *data) */ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET]; curl_socket_t data_sock = conn->sock[SECONDARYSOCKET]; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; int result; - long timeout_ms; + time_t timeout_ms; ssize_t nread; int ftpcode; @@ -455,7 +455,7 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received) result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0); /* see if the connection request is already here */ - switch (result) { + switch(result) { case -1: /* error */ /* let's die here */ failf(data, "Error while waiting for server connect"); @@ -475,7 +475,7 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received) if(ftpcode/100 > 3) return CURLE_FTP_ACCEPT_FAILED; - return CURLE_FTP_WEIRD_SERVER_REPLY; + return CURLE_WEIRD_SERVER_REPLY; } break; @@ -495,11 +495,11 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received) */ static CURLcode InitiateTransfer(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; CURLcode result = CURLE_OK; - if(conn->ssl[SECONDARYSOCKET].use) { + if(conn->bits.ftp_use_data_ssl) { /* since we only have a plaintext TCP connection here, we must now * do the TLS stuff */ infof(data, "Doing the SSL/TLS handshake on the data stream\n"); @@ -546,8 +546,8 @@ static CURLcode InitiateTransfer(struct connectdata *conn) */ static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected) { - struct SessionHandle *data = conn->data; - long timeout_ms; + struct Curl_easy *data = conn->data; + time_t timeout_ms; CURLcode result = CURLE_OK; *connected = FALSE; @@ -617,7 +617,7 @@ static CURLcode ftp_readresp(curl_socket_t sockfd, size_t *size) /* size of the response */ { struct connectdata *conn = pp->conn; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; #ifdef HAVE_GSSAPI char * const buf = data->state.buffer; #endif @@ -687,9 +687,9 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ * line in a response or continue reading. */ curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; - long timeout; /* timeout in milliseconds */ - long interval_ms; - struct SessionHandle *data = conn->data; + time_t timeout; /* timeout in milliseconds */ + time_t interval_ms; + struct Curl_easy *data = conn->data; CURLcode result = CURLE_OK; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; @@ -740,8 +740,8 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */ * wait for more data anyway. */ } - else { - switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, interval_ms)) { + else if(!Curl_conn_data_pending(conn, FIRSTSOCKET)) { + switch(SOCKET_READABLE(sockfd, interval_ms)) { case -1: /* select() error, stop reading */ failf(data, "FTP response aborted due to select/poll error: %d", SOCKERRNO); @@ -911,7 +911,7 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, } else { socks[1] = conn->sock[SECONDARYSOCKET]; - bits |= GETSOCK_WRITESOCK(1); + bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1); } return bits; @@ -980,7 +980,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, { CURLcode result = CURLE_OK; struct ftp_conn *ftpc = &conn->proto.ftpc; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; curl_socket_t portsock= CURL_SOCKET_BAD; char myhost[256] = ""; @@ -1035,7 +1035,8 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(*string_ftpport == '[') { /* [ipv6]:port(-range) */ ip_start = string_ftpport + 1; - if((ip_end = strchr(string_ftpport, ']')) != NULL) + ip_end = strchr(string_ftpport, ']'); + if(ip_end) strncpy(addr, ip_start, ip_end - ip_start); } else @@ -1043,30 +1044,35 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, if(*string_ftpport == ':') { /* :port */ ip_end = string_ftpport; - } - else if((ip_end = strchr(string_ftpport, ':')) != NULL) { - /* either ipv6 or (ipv4|domain|interface):port(-range) */ -#ifdef ENABLE_IPV6 - if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) { - /* ipv6 */ - port_min = port_max = 0; - strcpy(addr, string_ftpport); - ip_end = NULL; /* this got no port ! */ } - else + else { + ip_end = strchr(string_ftpport, ':'); + if(ip_end) { + /* either ipv6 or (ipv4|domain|interface):port(-range) */ +#ifdef ENABLE_IPV6 + if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) { + /* ipv6 */ + port_min = port_max = 0; + strcpy(addr, string_ftpport); + ip_end = NULL; /* this got no port ! */ + } + else #endif - /* (ipv4|domain|interface):port(-range) */ - strncpy(addr, string_ftpport, ip_end - ip_start); - } - else - /* ipv4|interface */ - strcpy(addr, string_ftpport); + /* (ipv4|domain|interface):port(-range) */ + strncpy(addr, string_ftpport, ip_end - ip_start); + } + else + /* ipv4|interface */ + strcpy(addr, string_ftpport); + } /* parse the port */ if(ip_end != NULL) { - if((port_start = strchr(ip_end, ':')) != NULL) { + port_start = strchr(ip_end, ':'); + if(port_start) { port_min = curlx_ultous(strtoul(port_start+1, NULL, 10)); - if((port_sep = strchr(port_start, '-')) != NULL) { + port_sep = strchr(port_start, '-'); + if(port_sep) { port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10)); } else @@ -1403,7 +1409,7 @@ static CURLcode ftp_state_prepare_transfer(struct connectdata *conn) { CURLcode result = CURLE_OK; struct FTP *ftp = conn->data->req.protop; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(ftp->transfer != FTPTRANSFER_BODY) { /* doesn't transfer any data */ @@ -1486,7 +1492,7 @@ static CURLcode ftp_state_size(struct connectdata *conn) static CURLcode ftp_state_list(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* If this output is to be machine-parsed, the NLST command might be better to use, since the LIST command output is not specified or standard in any @@ -1575,7 +1581,7 @@ static CURLcode ftp_state_type(struct connectdata *conn) { CURLcode result = CURLE_OK; struct FTP *ftp = conn->data->req.protop; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; /* If we have selected NOBODY and HEADER, it means that we only want file @@ -1607,7 +1613,7 @@ static CURLcode ftp_state_type(struct connectdata *conn) static CURLcode ftp_state_mdtm(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; /* Requested time of file or time-depended transfer? */ @@ -1632,7 +1638,7 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn, { CURLcode result = CURLE_OK; struct FTP *ftp = conn->data->req.protop; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; int seekerr = CURL_SEEKFUNC_OK; @@ -1728,7 +1734,7 @@ static CURLcode ftp_state_quote(struct connectdata *conn, ftpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; bool quote=FALSE; @@ -1835,7 +1841,7 @@ static CURLcode ftp_epsv_disable(struct connectdata *conn) if(conn->bits.ipv6) { /* We can't disable EPSV when doing IPv6, so this is instead a fail */ failf(conn->data, "Failed EPSV attempt, exiting\n"); - return CURLE_FTP_WEIRD_SERVER_REPLY; + return CURLE_WEIRD_SERVER_REPLY; } infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n"); @@ -1850,84 +1856,6 @@ static CURLcode ftp_epsv_disable(struct connectdata *conn) return result; } -/* - * Perform the necessary magic that needs to be done once the TCP connection - * to the proxy has completed. - */ -static CURLcode proxy_magic(struct connectdata *conn, - char *newhost, unsigned short newport, - bool *magicdone) -{ - CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; - -#if defined(CURL_DISABLE_PROXY) - (void) newhost; - (void) newport; -#endif - - *magicdone = FALSE; - - switch(conn->proxytype) { - case CURLPROXY_SOCKS5: - case CURLPROXY_SOCKS5_HOSTNAME: - result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, - newport, SECONDARYSOCKET, conn); - *magicdone = TRUE; - break; - case CURLPROXY_SOCKS4: - result = Curl_SOCKS4(conn->proxyuser, newhost, newport, - SECONDARYSOCKET, conn, FALSE); - *magicdone = TRUE; - break; - case CURLPROXY_SOCKS4A: - result = Curl_SOCKS4(conn->proxyuser, newhost, newport, - SECONDARYSOCKET, conn, TRUE); - *magicdone = TRUE; - break; - case CURLPROXY_HTTP: - case CURLPROXY_HTTP_1_0: - /* do nothing here. handled later. */ - break; - default: - failf(data, "unknown proxytype option given"); - result = CURLE_COULDNT_CONNECT; - break; - } - - if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { - /* BLOCKING */ - /* We want "seamless" FTP operations through HTTP proxy tunnel */ - - /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the - * member conn->proto.http; we want FTP through HTTP and we have to - * change the member temporarily for connecting to the HTTP proxy. After - * Curl_proxyCONNECT we have to set back the member to the original - * struct FTP pointer - */ - struct HTTP http_proxy; - struct FTP *ftp_save = data->req.protop; - memset(&http_proxy, 0, sizeof(http_proxy)); - data->req.protop = &http_proxy; - - result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport, TRUE); - - data->req.protop = ftp_save; - - if(result) - return result; - - if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) { - /* the CONNECT procedure is not complete, the tunnel is not yet up */ - state(conn, FTP_STOP); /* this phase is completed */ - return result; - } - else - *magicdone = TRUE; - } - - return result; -} static char *control_address(struct connectdata *conn) { @@ -1935,11 +1863,7 @@ static char *control_address(struct connectdata *conn) If a proxy tunnel is used, returns the original host name instead, because the effective control connection address is the proxy address, not the ftp host. */ - if(conn->bits.tunnel_proxy || - conn->proxytype == CURLPROXY_SOCKS5 || - conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME || - conn->proxytype == CURLPROXY_SOCKS4 || - conn->proxytype == CURLPROXY_SOCKS4A) + if(conn->bits.tunnel_proxy || conn->bits.socksproxy) return conn->host.name; return conn->ip_addr_str; @@ -1950,7 +1874,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, { struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; struct Curl_dns_entry *addr=NULL; int rc; unsigned short connectport; /* the local port connect() should use! */ @@ -2063,7 +1987,9 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, * here. We don't want to rely on a former host lookup that might've * expired now, instead we remake the lookup here and now! */ - rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr); + const char * const host_name = conn->bits.socksproxy ? + conn->socks_proxy.host.name : conn->http_proxy.host.name; + rc = Curl_resolv(conn, host_name, (int)conn->port, &addr); if(rc == CURLRESOLV_PENDING) /* BLOCKING, ignores the return code but 'addr' will be NULL in case of failure */ @@ -2073,9 +1999,8 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, (unsigned short)conn->port; /* we connect to the proxy's port */ if(!addr) { - failf(data, "Can't resolve proxy host %s:%hu", - conn->proxy.name, connectport); - return CURLE_FTP_CANT_GET_HOST; + failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport); + return CURLE_COULDNT_RESOLVE_PROXY; } } else { @@ -2115,6 +2040,10 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, /* this just dumps information about this second connection */ ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport); + Curl_safefree(conn->secondaryhostname); + conn->secondaryhostname = strdup(ftpc->newhost); + conn->secondary_port = ftpc->newport; + Curl_resolv_unlock(data, addr); /* we're done using this address */ conn->bits.do_more = TRUE; state(conn, FTP_STOP); /* this phase is completed */ @@ -2125,7 +2054,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, static CURLcode ftp_state_port_resp(struct connectdata *conn, int ftpcode) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; ftpport fcmd = (ftpport)ftpc->count1; CURLcode result = CURLE_OK; @@ -2162,7 +2091,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, int ftpcode) { CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; @@ -2178,7 +2107,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, /* we have a time, reformat it */ time_t secs=time(NULL); /* using the good old yacc/bison yuck */ - snprintf(buf, sizeof(conn->data->state.buffer), + snprintf(buf, CURL_BUFSIZE(conn->data->set.buffer_size), "%04d%02d%02d %02d:%02d:%02d GMT", year, month, day, hour, minute, second); /* now, convert this into a time() value: */ @@ -2267,7 +2196,7 @@ static CURLcode ftp_state_type_resp(struct connectdata *conn, ftpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; if(ftpcode/100 != 2) { /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a @@ -2296,7 +2225,7 @@ static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize) { CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; @@ -2379,7 +2308,7 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn, ftpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; curl_off_t filesize; char *buf = data->state.buffer; @@ -2389,7 +2318,7 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn, if(instate == FTP_SIZE) { #ifdef CURL_FTP_HTTPSTYLE_HEAD if(-1 != filesize) { - snprintf(buf, sizeof(data->state.buffer), + snprintf(buf, CURL_BUFSIZE(data->set.buffer_size), "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize); result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0); if(result) @@ -2451,7 +2380,7 @@ static CURLcode ftp_state_stor_resp(struct connectdata *conn, int ftpcode, ftpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(ftpcode>=400) { failf(data, "Failed FTP upload: %0d", ftpcode); @@ -2490,7 +2419,7 @@ static CURLcode ftp_state_get_resp(struct connectdata *conn, ftpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; char *buf = data->state.buffer; @@ -2647,7 +2576,7 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn, ftpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; (void)instate; /* no use for this yet */ @@ -2702,7 +2631,7 @@ static CURLcode ftp_state_acct_resp(struct connectdata *conn, int ftpcode) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(ftpcode != 230) { failf(data, "ACCT rejected by server: %03d", ftpcode); result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */ @@ -2718,7 +2647,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) { CURLcode result; curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; int ftpcode; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; @@ -2742,7 +2671,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) else if(ftpcode != 220) { failf(data, "Got a %03d ftp-server response when 220 was expected", ftpcode); - return CURLE_FTP_WEIRD_SERVER_REPLY; + return CURLE_WEIRD_SERVER_REPLY; } /* We have received a 220 response fine, now we proceed. */ @@ -2763,7 +2692,10 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) } #endif - if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { + if(data->set.use_ssl && + (!conn->ssl[FIRSTSOCKET].use || + (conn->bits.proxy_ssl_connected[FIRSTSOCKET] && + !conn->proxy_ssl[FIRSTSOCKET].use))) { /* We don't have a SSL/TLS connection yet, but FTPS is requested. Try a FTPS connection now */ @@ -2808,7 +2740,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) /* Curl_ssl_connect is BLOCKING */ result = Curl_ssl_connect(conn, FIRSTSOCKET); if(!result) { - conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */ + conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */ result = ftp_state_user(conn); } } @@ -2850,7 +2782,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) case FTP_PROT: if(ftpcode/100 == 2) /* We have enabled SSL for the data connection! */ - conn->ssl[SECONDARYSOCKET].use = + conn->bits.ftp_use_data_ssl = (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE; /* FTP servers typically responds with 500 if they decide to reject our 'P' request */ @@ -2891,6 +2823,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) case FTP_PWD: if(ftpcode == 257) { char *ptr=&data->state.buffer[4]; /* start on the first letter */ + const size_t buf_size = CURL_BUFSIZE(data->set.buffer_size); char *dir; char *store; @@ -2908,7 +2841,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) */ /* scan for the first double-quote for non-standard responses */ - while(ptr < &data->state.buffer[sizeof(data->state.buffer)] + while(ptr < &data->state.buffer[buf_size] && *ptr != '\n' && *ptr != '\0' && *ptr != '"') ptr++; @@ -2999,7 +2932,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) /* Check for special servers here. */ - if(strequal(os, "OS/400")) { + if(strcasecompare(os, "OS/400")) { /* Force OS400 name format 1. */ result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1"); if(result) { @@ -3165,7 +3098,7 @@ static CURLcode ftp_multi_statemach(struct connectdata *conn, struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE); - /* Check for the state outside of the Curl_socket_ready() return code checks + /* Check for the state outside of the Curl_socket_check() return code checks since at times we are in fact already in this state when this function gets called. */ *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE; @@ -3243,15 +3176,14 @@ static CURLcode ftp_connect(struct connectdata *conn, static CURLcode ftp_done(struct connectdata *conn, CURLcode status, bool premature) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; struct pingpong *pp = &ftpc->pp; ssize_t nread; int ftpcode; CURLcode result = CURLE_OK; - bool was_ctl_valid = ftpc->ctl_valid; - char *path; + char *path = NULL; const char *path_to_use = data->state.path; if(!ftp) @@ -3274,10 +3206,9 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, /* the connection stays alive fine even though this happened */ /* fall-through */ case CURLE_OK: /* doesn't affect the control connection's status */ - if(!premature) { - ftpc->ctl_valid = was_ctl_valid; + if(!premature) break; - } + /* until we cope better with prematurely ended requests, let them * fallback as if in complete failure */ default: /* by default, an error means the control connection is @@ -3300,13 +3231,12 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, ftpc->known_filesize = -1; } - /* get the "raw" path */ - path = curl_easy_unescape(data, path_to_use, 0, NULL); - if(!path) { - /* out of memory, but we can limp along anyway (and should try to - * since we may already be in the out of memory cleanup path) */ - if(!result) - result = CURLE_OUT_OF_MEMORY; + if(!result) + /* get the "raw" path */ + result = Curl_urldecode(data, path_to_use, 0, &path, NULL, FALSE); + if(result) { + /* We can limp along anyway (and should try to since we may already be in + * the error path) */ ftpc->ctl_valid = FALSE; /* mark control connection as bad */ connclose(conn, "FTP: out of memory!"); /* mark for connection closure */ ftpc->prevpath = NULL; /* no path remembering */ @@ -3587,7 +3517,7 @@ static CURLcode ftp_range(struct connectdata *conn) curl_off_t from, to; char *ptr; char *ptr2; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; if(data->state.use_range && data->state.range) { @@ -3645,7 +3575,7 @@ static CURLcode ftp_range(struct connectdata *conn) static CURLcode ftp_do_more(struct connectdata *conn, int *completep) { - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; CURLcode result = CURLE_OK; bool connected = FALSE; @@ -3669,10 +3599,6 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep) /* Ready to do more? */ if(connected) { DEBUGF(infof(data, "DO-MORE connected phase starts\n")); - if(conn->bits.proxy) { - infof(data, "Connection to proxy confirmed\n"); - result = proxy_magic(conn, ftpc->newhost, ftpc->newport, &connected); - } } else { if(result && (ftpc->count1 == 0)) { @@ -3684,6 +3610,18 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep) } } + result = Curl_proxy_connect(conn, SECONDARYSOCKET); + if(result) + return result; + + if(CONNECT_SECONDARYSOCKET_PROXY_SSL()) + return result; + + if(conn->bits.tunnel_proxy && conn->bits.httpproxy && + conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) + return result; + + if(ftpc->state) { /* already in a state so skip the intial commands. They are only done to kickstart the do_more state */ @@ -3942,7 +3880,7 @@ static CURLcode wc_statemach(struct connectdata *conn) struct WildcardData * const wildcard = &(conn->data->wildcard); CURLcode result = CURLE_OK; - switch (wildcard->state) { + switch(wildcard->state) { case CURLWC_INIT: result = init_wc_data(conn); if(wildcard->state == CURLWC_CLEAN) @@ -4093,8 +4031,7 @@ static CURLcode ftp_do(struct connectdata *conn, bool *done) } -CURLcode Curl_ftpsendf(struct connectdata *conn, - const char *fmt, ...) +CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd) { ssize_t bytes_written; #define SBUF_SIZE 1024 @@ -4106,10 +4043,9 @@ CURLcode Curl_ftpsendf(struct connectdata *conn, enum protection_level data_sec = conn->data_prot; #endif - va_list ap; - va_start(ap, fmt); - write_len = vsnprintf(s, SBUF_SIZE-3, fmt, ap); - va_end(ap); + write_len = strlen(cmd); + if(write_len > (sizeof(s) -3)) + return CURLE_BAD_FUNCTION_ARGUMENT; strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */ write_len +=2; @@ -4209,7 +4145,7 @@ static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection) (void)ftp_quit(conn); /* ignore errors on the QUIT */ if(ftpc->entrypath) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) { data->state.most_recent_ftp_entrypath = NULL; } @@ -4242,7 +4178,7 @@ static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection) static CURLcode ftp_parse_url_path(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* the ftp struct is already inited in ftp_connect() */ struct FTP *ftp = data->req.protop; struct ftp_conn *ftpc = &conn->proto.ftpc; @@ -4251,8 +4187,8 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) const char *cur_pos; const char *filename = NULL; - cur_pos = path_to_use; /* current position in path. point at the begin - of next path component */ + cur_pos = path_to_use; /* current position in path. point at the begin of + next path component */ ftpc->ctl_valid = FALSE; ftpc->cwdfail = FALSE; @@ -4291,6 +4227,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) slash_pos=strrchr(cur_pos, '/'); if(slash_pos || !*cur_pos) { size_t dirlen = slash_pos-cur_pos; + CURLcode result; ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0])); if(!ftpc->dirs) @@ -4299,12 +4236,13 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) if(!dirlen) dirlen++; - ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/", - slash_pos ? curlx_uztosi(dirlen) : 1, - NULL); - if(!ftpc->dirs[0]) { + result = Curl_urldecode(conn->data, slash_pos ? cur_pos : "/", + slash_pos ? dirlen : 1, + &ftpc->dirs[0], NULL, + FALSE); + if(result) { freedirs(ftpc); - return CURLE_OUT_OF_MEMORY; + return result; } ftpc->dirdepth = 1; /* we consider it to be a single dir */ filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */ @@ -4322,7 +4260,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) return CURLE_OUT_OF_MEMORY; /* we have a special case for listing the root dir only */ - if(strequal(path_to_use, "/")) { + if(!strcmp(path_to_use, "/")) { cur_pos++; /* make it point to the zero byte */ ftpc->dirs[0] = strdup("/"); ftpc->dirdepth++; @@ -4339,18 +4277,15 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) /* we skip empty path components, like "x//y" since the FTP command CWD requires a parameter and a non-existent parameter a) doesn't work on many servers and b) has no effect on the others. */ - int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir); - ftpc->dirs[ftpc->dirdepth] = - curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL); - if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */ - failf(data, "no memory"); - freedirs(ftpc); - return CURLE_OUT_OF_MEMORY; - } - if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) { + size_t len = slash_pos - cur_pos + absolute_dir; + CURLcode result = + Curl_urldecode(conn->data, cur_pos - absolute_dir, len, + &ftpc->dirs[ftpc->dirdepth], NULL, + TRUE); + if(result) { free(ftpc->dirs[ftpc->dirdepth]); freedirs(ftpc); - return CURLE_URL_MALFORMAT; + return result; } } else { @@ -4386,15 +4321,12 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) } /* switch */ if(filename && *filename) { - ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL); - if(NULL == ftpc->file) { + CURLcode result = + Curl_urldecode(conn->data, filename, 0, &ftpc->file, NULL, TRUE); + + if(result) { freedirs(ftpc); - failf(data, "no memory"); - return CURLE_OUT_OF_MEMORY; - } - if(isBadFtpString(ftpc->file)) { - freedirs(ftpc); - return CURLE_URL_MALFORMAT; + return result; } } else @@ -4412,16 +4344,18 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) if(ftpc->prevpath) { /* prevpath is "raw" so we convert the input path before we compare the strings */ - int dlen; - char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen); - if(!path) { + size_t dlen; + char *path; + CURLcode result = + Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, FALSE); + if(result) { freedirs(ftpc); - return CURLE_OUT_OF_MEMORY; + return result; } - dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0; - if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) && - strnequal(path, ftpc->prevpath, dlen)) { + dlen -= ftpc->file?strlen(ftpc->file):0; + if((dlen == strlen(ftpc->prevpath)) && + !strncmp(path, ftpc->prevpath, dlen)) { infof(data, "Request has same path as previous transfer\n"); ftpc->cwddone = TRUE; } @@ -4494,7 +4428,7 @@ CURLcode ftp_regular_transfer(struct connectdata *conn, { CURLcode result=CURLE_OK; bool connected=FALSE; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ftp_conn *ftpc = &conn->proto.ftpc; data->req.size = -1; /* make sure this is unknown at this point */ @@ -4528,7 +4462,7 @@ CURLcode ftp_regular_transfer(struct connectdata *conn, static CURLcode ftp_setup_connection(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char *type; char command; struct FTP *ftp; @@ -4574,7 +4508,7 @@ static CURLcode ftp_setup_connection(struct connectdata *conn) command = Curl_raw_toupper(type[6]); conn->bits.type_set = TRUE; - switch (command) { + switch(command) { case 'A': /* ASCII mode */ data->set.prefer_ascii = TRUE; break; diff --git a/contrib/curl/lib/ftp.h b/contrib/curl/lib/ftp.h index 7495e3e0..3bbf2620 100644 --- a/contrib/curl/lib/ftp.h +++ b/contrib/curl/lib/ftp.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -31,7 +31,7 @@ extern const struct Curl_handler Curl_handler_ftp; extern const struct Curl_handler Curl_handler_ftps; #endif -CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...); +CURLcode Curl_ftpsend(struct connectdata *, const char *cmd); CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn, int *ftpcode); #endif /* CURL_DISABLE_FTP */ @@ -97,9 +97,9 @@ typedef enum { file */ } curl_ftpfile; -/* This FTP struct is used in the SessionHandle. All FTP data that is +/* This FTP struct is used in the Curl_easy. All FTP data that is connection-oriented must be in FTP_conn to properly deal with the fact that - perhaps the SessionHandle is changed between the times the connection is + perhaps the Curl_easy is changed between the times the connection is used. */ struct FTP { curl_off_t *bytecountp; @@ -143,7 +143,7 @@ struct ftp_conn { ftpstate state_saved; /* transfer type saved to be reloaded after data connection is established */ curl_off_t retr_size_saved; /* Size of retrieved file saved */ - char * server_os; /* The target server operating system. */ + char *server_os; /* The target server operating system. */ curl_off_t known_filesize; /* file size is different from -1, if wildcard LIST parsing was done and wc_statemach set it */ diff --git a/contrib/curl/lib/ftplistparser.c b/contrib/curl/lib/ftplistparser.c index abbf76e2..f94b31b9 100644 --- a/contrib/curl/lib/ftplistparser.c +++ b/contrib/curl/lib/ftplistparser.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -45,7 +45,6 @@ #include "fileinfo.h" #include "llist.h" #include "strtoofft.h" -#include "rawstr.h" #include "ftp.h" #include "ftplistparser.h" #include "curl_fnmatch.h" @@ -397,9 +396,9 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, } } - switch (parser->os_type) { + switch(parser->os_type) { case OS_TYPE_UNIX: - switch (parser->state.UNIX.main) { + switch(parser->state.UNIX.main) { case PL_UNIX_TOTALSIZE: switch(parser->state.UNIX.sub.total_dirsize) { case PL_UNIX_TOTALSIZE_INIT: @@ -448,7 +447,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, } break; case PL_UNIX_FILETYPE: - switch (c) { + switch(c) { case '-': finfo->filetype = CURLFILETYPE_FILE; break; @@ -968,7 +967,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb, } break; case PL_WINNT_FILENAME: - switch (parser->state.NT.sub.filename) { + switch(parser->state.NT.sub.filename) { case PL_WINNT_FILENAME_PRESPACE: if(c != ' ') { parser->item_offset = finfo->b_used -1; diff --git a/contrib/curl/lib/getenv.c b/contrib/curl/lib/getenv.c index 50bb79f5..89d181de 100644 --- a/contrib/curl/lib/getenv.c +++ b/contrib/curl/lib/getenv.c @@ -30,7 +30,8 @@ static char *GetEnv(const char *variable) { -#ifdef _WIN32_WCE +#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP) + (void)variable; return NULL; #else #ifdef WIN32 diff --git a/contrib/curl/lib/getinfo.c b/contrib/curl/lib/getinfo.c index d4b01bf2..a1ce5058 100644 --- a/contrib/curl/lib/getinfo.c +++ b/contrib/curl/lib/getinfo.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -36,10 +36,13 @@ #include "memdebug.h" /* - * This is supposed to be called in the beginning of a perform() session - * and should reset all session-info variables + * Initialize statistical and informational data. + * + * This function is called in curl_easy_reset, curl_easy_duphandle and at the + * beginning of a perform session. It must reset the session-info variables, + * in particular all variables in struct PureInfo. */ -CURLcode Curl_initinfo(struct SessionHandle *data) +CURLcode Curl_initinfo(struct Curl_easy *data) { struct Progress *pro = &data->progress; struct PureInfo *info = &data->info; @@ -58,23 +61,35 @@ CURLcode Curl_initinfo(struct SessionHandle *data) info->filetime = -1; /* -1 is an illegal time and thus means unknown */ info->timecond = FALSE; + info->header_size = 0; + info->request_size = 0; + info->proxyauthavail = 0; + info->httpauthavail = 0; + info->numconnects = 0; + free(info->contenttype); info->contenttype = NULL; - info->header_size = 0; - info->request_size = 0; - info->numconnects = 0; + free(info->wouldredirect); + info->wouldredirect = NULL; info->conn_primary_ip[0] = '\0'; info->conn_local_ip[0] = '\0'; info->conn_primary_port = 0; info->conn_local_port = 0; + info->conn_scheme = 0; + info->conn_protocol = 0; + +#ifdef USE_SSL + Curl_ssl_free_certinfo(data); +#endif + return CURLE_OK; } -static CURLcode getinfo_char(struct SessionHandle *data, CURLINFO info, - char **param_charp) +static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info, + const char **param_charp) { switch(info) { case CURLINFO_EFFECTIVE_URL: @@ -111,6 +126,9 @@ static CURLcode getinfo_char(struct SessionHandle *data, CURLINFO info, case CURLINFO_RTSP_SESSION_ID: *param_charp = data->set.str[STRING_RTSP_SESSION_ID]; break; + case CURLINFO_SCHEME: + *param_charp = data->info.conn_scheme; + break; default: return CURLE_UNKNOWN_OPTION; @@ -119,7 +137,7 @@ static CURLcode getinfo_char(struct SessionHandle *data, CURLINFO info, return CURLE_OK; } -static CURLcode getinfo_long(struct SessionHandle *data, CURLINFO info, +static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info, long *param_longp) { curl_socket_t sockfd; @@ -148,6 +166,9 @@ static CURLcode getinfo_long(struct SessionHandle *data, CURLINFO info, case CURLINFO_SSL_VERIFYRESULT: *param_longp = data->set.ssl.certverifyresult; break; + case CURLINFO_PROXY_SSL_VERIFYRESULT: + *param_longp = data->set.proxy_ssl.certverifyresult; + break; case CURLINFO_REDIRECT_COUNT: *param_longp = data->set.followlocation; break; @@ -198,6 +219,25 @@ static CURLcode getinfo_long(struct SessionHandle *data, CURLINFO info, case CURLINFO_RTSP_CSEQ_RECV: *param_longp = data->state.rtsp_CSeq_recv; break; + case CURLINFO_HTTP_VERSION: + switch(data->info.httpversion) { + case 10: + *param_longp = CURL_HTTP_VERSION_1_0; + break; + case 11: + *param_longp = CURL_HTTP_VERSION_1_1; + break; + case 20: + *param_longp = CURL_HTTP_VERSION_2_0; + break; + default: + *param_longp = CURL_HTTP_VERSION_NONE; + break; + } + break; + case CURLINFO_PROTOCOL: + *param_longp = data->info.conn_protocol; + break; default: return CURLE_UNKNOWN_OPTION; @@ -206,7 +246,7 @@ static CURLcode getinfo_long(struct SessionHandle *data, CURLINFO info, return CURLE_OK; } -static CURLcode getinfo_double(struct SessionHandle *data, CURLINFO info, +static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info, double *param_doublep) { switch(info) { @@ -259,7 +299,7 @@ static CURLcode getinfo_double(struct SessionHandle *data, CURLINFO info, return CURLE_OK; } -static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info, +static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info, struct curl_slist **param_slistp) { union { @@ -335,7 +375,7 @@ static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info, return CURLE_OK; } -static CURLcode getinfo_socket(struct SessionHandle *data, CURLINFO info, +static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info, curl_socket_t *param_socketp) { switch(info) { @@ -349,12 +389,12 @@ static CURLcode getinfo_socket(struct SessionHandle *data, CURLINFO info, return CURLE_OK; } -CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) +CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...) { va_list arg; long *param_longp = NULL; double *param_doublep = NULL; - char **param_charp = NULL; + const char **param_charp = NULL; struct curl_slist **param_slistp = NULL; curl_socket_t *param_socketp = NULL; int type; @@ -368,7 +408,7 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) type = CURLINFO_TYPEMASK & (int)info; switch(type) { case CURLINFO_STRING: - param_charp = va_arg(arg, char **); + param_charp = va_arg(arg, const char **); if(param_charp) result = getinfo_char(data, info, param_charp); break; diff --git a/contrib/curl/lib/getinfo.h b/contrib/curl/lib/getinfo.h index 4c2c1684..aecf717f 100644 --- a/contrib/curl/lib/getinfo.h +++ b/contrib/curl/lib/getinfo.h @@ -21,7 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ -CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...); -CURLcode Curl_initinfo(struct SessionHandle *data); +CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...); +CURLcode Curl_initinfo(struct Curl_easy *data); #endif /* HEADER_CURL_GETINFO_H */ diff --git a/contrib/curl/lib/gopher.c b/contrib/curl/lib/gopher.c index 19f2f5a8..a073d0ba 100644 --- a/contrib/curl/lib/gopher.c +++ b/contrib/curl/lib/gopher.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -28,13 +28,11 @@ #include #include "transfer.h" #include "sendf.h" - #include "progress.h" -#include "strequal.h" #include "gopher.h" -#include "rawstr.h" #include "select.h" #include "url.h" +#include "escape.h" #include "warnless.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -75,7 +73,7 @@ const struct Curl_handler Curl_handler_gopher = { static CURLcode gopher_do(struct connectdata *conn, bool *done) { CURLcode result=CURLE_OK; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; curl_off_t *bytecount = &data->req.bytecount; @@ -83,7 +81,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) char *sel; char *sel_org = NULL; ssize_t amount, k; - int len; + size_t len; *done = TRUE; /* unconditionally */ @@ -107,7 +105,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) newp[i] = '\x09'; /* ... and finally unescape */ - sel = curl_easy_unescape(data, newp, 0, &len); + result = Curl_urldecode(data, newp, 0, &sel, &len, FALSE); if(!sel) return CURLE_OUT_OF_MEMORY; sel_org = sel; @@ -121,20 +119,17 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) result = Curl_write(conn, sockfd, sel, k, &amount); if(!result) { /* Which may not have written it all! */ result = Curl_client_write(conn, CLIENTWRITE_HEADER, sel, amount); - if(result) { - free(sel_org); - return result; - } + if(result) + break; + k -= amount; sel += amount; if(k < 1) break; /* but it did write it all */ } - else { - failf(data, "Failed sending Gopher request"); - free(sel_org); - return result; - } + else + break; + /* Don't busyloop. The entire loop thing is a work-around as it causes a BLOCKING behavior which is a NO-NO. This function should rather be split up in a do and a doing piece where the pieces that aren't @@ -144,14 +139,18 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done) Wait a while for the socket to be writable. Note that this doesn't acknowledge the timeout. */ - Curl_socket_ready(CURL_SOCKET_BAD, sockfd, 100); + if(SOCKET_WRITABLE(sockfd, 100) < 0) { + result = CURLE_SEND_ERROR; + break; + } } free(sel_org); - /* We can use Curl_sendf to send the terminal \r\n relatively safely and - save allocing another string/doing another _write loop. */ - result = Curl_sendf(sockfd, conn, "\r\n"); + if(!result) + /* We can use Curl_sendf to send the terminal \r\n relatively safely and + save allocing another string/doing another _write loop. */ + result = Curl_sendf(sockfd, conn, "\r\n"); if(result) { failf(data, "Failed sending Gopher request"); return result; diff --git a/contrib/curl/lib/hash.c b/contrib/curl/lib/hash.c index 937381b6..06550423 100644 --- a/contrib/curl/lib/hash.c +++ b/contrib/curl/lib/hash.c @@ -135,7 +135,7 @@ Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p) { struct curl_hash_element *he; struct curl_llist_element *le; - struct curl_llist *l = FETCH_LIST (h, key, key_len); + struct curl_llist *l = FETCH_LIST(h, key, key_len); for(le = l->head; le; le = le->next) { he = (struct curl_hash_element *) le->ptr; @@ -291,9 +291,9 @@ Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, } } -size_t Curl_hash_str(void* key, size_t key_length, size_t slots_num) +size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num) { - const char* key_str = (const char *) key; + const char *key_str = (const char *) key; const char *end = key_str + key_length; unsigned long h = 5381; diff --git a/contrib/curl/lib/hash.h b/contrib/curl/lib/hash.h index 57a17f02..a5a6cac7 100644 --- a/contrib/curl/lib/hash.h +++ b/contrib/curl/lib/hash.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -29,16 +29,16 @@ #include "llist.h" /* Hash function prototype */ -typedef size_t (*hash_function) (void* key, +typedef size_t (*hash_function) (void *key, size_t key_length, size_t slots_num); /* Comparator function prototype. Compares two keys. */ -typedef size_t (*comp_function) (void* key1, +typedef size_t (*comp_function) (void *key1, size_t key1_len, - void*key2, + void *key2, size_t key2_len); typedef void (*curl_hash_dtor)(void *); @@ -76,7 +76,7 @@ int Curl_hash_init(struct curl_hash *h, void *Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p); int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len); -void *Curl_hash_pick(struct curl_hash *, void * key, size_t key_len); +void *Curl_hash_pick(struct curl_hash *, void *key, size_t key_len); void Curl_hash_apply(struct curl_hash *h, void *user, void (*cb)(void *user, void *ptr)); int Curl_hash_count(struct curl_hash *h); @@ -84,10 +84,9 @@ void Curl_hash_destroy(struct curl_hash *h); void Curl_hash_clean(struct curl_hash *h); void Curl_hash_clean_with_criterium(struct curl_hash *h, void *user, int (*comp)(void *, void *)); -size_t Curl_hash_str(void* key, size_t key_length, size_t slots_num); -size_t Curl_str_key_compare(void*k1, size_t key1_len, void*k2, +size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num); +size_t Curl_str_key_compare(void *k1, size_t key1_len, void *k2, size_t key2_len); - void Curl_hash_start_iterate(struct curl_hash *hash, struct curl_hash_iterator *iter); struct curl_hash_element * diff --git a/contrib/curl/lib/hmac.c b/contrib/curl/lib/hmac.c index 3df47158..dae95054 100644 --- a/contrib/curl/lib/hmac.c +++ b/contrib/curl/lib/hmac.c @@ -49,12 +49,12 @@ static const unsigned char hmac_opad = 0x5C; HMAC_context * Curl_HMAC_init(const HMAC_params * hashparams, - const unsigned char * key, + const unsigned char *key, unsigned int keylen) { size_t i; - HMAC_context * ctxt; - unsigned char * hkey; + HMAC_context *ctxt; + unsigned char *hkey; unsigned char b; /* Create HMAC context. */ @@ -101,7 +101,7 @@ Curl_HMAC_init(const HMAC_params * hashparams, } int Curl_HMAC_update(HMAC_context * ctxt, - const unsigned char * data, + const unsigned char *data, unsigned int len) { /* Update first hash calculation. */ @@ -110,7 +110,7 @@ int Curl_HMAC_update(HMAC_context * ctxt, } -int Curl_HMAC_final(HMAC_context * ctxt, unsigned char * result) +int Curl_HMAC_final(HMAC_context *ctxt, unsigned char *result) { const HMAC_params * hashparams = ctxt->hmac_hash; diff --git a/contrib/curl/lib/hostasyn.c b/contrib/curl/lib/hostasyn.c index c96734a5..28bdf7a4 100644 --- a/contrib/curl/lib/hostasyn.c +++ b/contrib/curl/lib/hostasyn.c @@ -77,7 +77,7 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn, if(CURL_ASYNC_SUCCESS == status) { if(ai) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); diff --git a/contrib/curl/lib/hostcheck.c b/contrib/curl/lib/hostcheck.c index 4db9e6ba..cbd08936 100644 --- a/contrib/curl/lib/hostcheck.c +++ b/contrib/curl/lib/hostcheck.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,7 +22,10 @@ #include "curl_setup.h" -#if defined(USE_OPENSSL) || defined(USE_AXTLS) || defined(USE_GSKIT) +#if defined(USE_OPENSSL) \ + || defined(USE_AXTLS) \ + || defined(USE_GSKIT) \ + || (defined(USE_SCHANNEL) && defined(_WIN32_WCE)) /* these backends use functions from this file */ #ifdef HAVE_NETINET_IN_H @@ -30,7 +33,7 @@ #endif #include "hostcheck.h" -#include "rawstr.h" +#include "strcase.h" #include "inet_pton.h" #include "curl_memory.h" @@ -77,7 +80,7 @@ static int hostmatch(char *hostname, char *pattern) pattern_wildcard = strchr(pattern, '*'); if(pattern_wildcard == NULL) - return Curl_raw_equal(pattern, hostname) ? + return strcasecompare(pattern, hostname) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; /* detect IP address as hostname and fail the match if so */ @@ -94,16 +97,16 @@ static int hostmatch(char *hostname, char *pattern) pattern_label_end = strchr(pattern, '.'); if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL || pattern_wildcard > pattern_label_end || - Curl_raw_nequal(pattern, "xn--", 4)) { + strncasecompare(pattern, "xn--", 4)) { wildcard_enabled = 0; } if(!wildcard_enabled) - return Curl_raw_equal(pattern, hostname) ? + return strcasecompare(pattern, hostname) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; hostname_label_end = strchr(hostname, '.'); if(hostname_label_end == NULL || - !Curl_raw_equal(pattern_label_end, hostname_label_end)) + !strcasecompare(pattern_label_end, hostname_label_end)) return CURL_HOST_NOMATCH; /* The wildcard must match at least one character, so the left-most @@ -114,8 +117,8 @@ static int hostmatch(char *hostname, char *pattern) prefixlen = pattern_wildcard - pattern; suffixlen = pattern_label_end - (pattern_wildcard+1); - return Curl_raw_nequal(pattern, hostname, prefixlen) && - Curl_raw_nequal(pattern_wildcard+1, hostname_label_end - suffixlen, + return strncasecompare(pattern, hostname, prefixlen) && + strncasecompare(pattern_wildcard+1, hostname_label_end - suffixlen, suffixlen) ? CURL_HOST_MATCH : CURL_HOST_NOMATCH; } @@ -144,4 +147,4 @@ int Curl_cert_hostcheck(const char *match_pattern, const char *hostname) return res; } -#endif /* OPENSSL or AXTLS or GSKIT */ +#endif /* OPENSSL, AXTLS, GSKIT or schannel+wince */ diff --git a/contrib/curl/lib/hostip.c b/contrib/curl/lib/hostip.c index ead78de7..fa4bad98 100644 --- a/contrib/curl/lib/hostip.c +++ b/contrib/curl/lib/hostip.c @@ -172,7 +172,7 @@ Curl_printable_address(const Curl_addrinfo *ai, char *buf, size_t bufsize) const struct in6_addr *ipaddr6; #endif - switch (ai->ai_family) { + switch(ai->ai_family) { case AF_INET: sa4 = (const void *)ai->ai_addr; ipaddr4 = &sa4->sin_addr; @@ -254,7 +254,7 @@ hostcache_prune(struct curl_hash *hostcache, long cache_timeout, time_t now) * Library-wide function for pruning the DNS cache. This function takes and * returns the appropriate locks. */ -void Curl_hostcache_prune(struct SessionHandle *data) +void Curl_hostcache_prune(struct Curl_easy *data) { time_t now; @@ -293,7 +293,7 @@ fetch_addr(struct connectdata *conn, char *entry_id = NULL; struct Curl_dns_entry *dns = NULL; size_t entry_len; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Create an entry id, based upon the hostname and port */ entry_id = create_hostcache_id(hostname, port); @@ -345,7 +345,7 @@ Curl_fetch_addr(struct connectdata *conn, const char *hostname, int port) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct Curl_dns_entry *dns = NULL; if(data->share) @@ -372,7 +372,7 @@ Curl_fetch_addr(struct connectdata *conn, * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. */ struct Curl_dns_entry * -Curl_cache_addr(struct SessionHandle *data, +Curl_cache_addr(struct Curl_easy *data, Curl_addrinfo *addr, const char *hostname, int port) @@ -447,7 +447,7 @@ int Curl_resolv(struct connectdata *conn, struct Curl_dns_entry **entry) { struct Curl_dns_entry *dns = NULL; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result; int rc = CURLRESOLV_ERROR; /* default to failure */ @@ -568,7 +568,7 @@ int Curl_resolv_timeout(struct connectdata *conn, const char *hostname, int port, struct Curl_dns_entry **entry, - long timeoutms) + time_t timeoutms) { #ifdef USE_ALARM_TIMEOUT #ifdef HAVE_SIGACTION @@ -582,7 +582,7 @@ int Curl_resolv_timeout(struct connectdata *conn, #endif /* HAVE_SIGACTION */ volatile long timeout; volatile unsigned int prev_alarm = 0; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; #endif /* USE_ALARM_TIMEOUT */ int rc; @@ -603,11 +603,14 @@ int Curl_resolv_timeout(struct connectdata *conn, /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */ return Curl_resolv(conn, hostname, port, entry); - if(timeout < 1000) + if(timeout < 1000) { /* The alarm() function only provides integer second resolution, so if we want to wait less than one second we must bail out already now. */ + failf(data, + "remaining timeout of %ld too small to resolve via SIGALRM method", + timeout); return CURLRESOLV_TIMEDOUT; - + } /* This allows us to time-out from the name resolver, as the timeout will generate a signal and we will siglongjmp() from that here. This technique has problems (see alarmfunc). @@ -716,7 +719,7 @@ clean_up: * * May be called with 'data' == NULL for global cache. */ -void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns) +void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns) { if(data && data->share) Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); @@ -758,7 +761,7 @@ int Curl_mk_dnscache(struct curl_hash *hash) * can be done! */ -void Curl_hostcache_clean(struct SessionHandle *data, +void Curl_hostcache_clean(struct Curl_easy *data, struct curl_hash *hash) { if(data && data->share) @@ -771,7 +774,7 @@ void Curl_hostcache_clean(struct SessionHandle *data, } -CURLcode Curl_loadhostpairs(struct SessionHandle *data) +CURLcode Curl_loadhostpairs(struct Curl_easy *data) { struct curl_slist *hostp; char hostname[256]; diff --git a/contrib/curl/lib/hostip.h b/contrib/curl/lib/hostip.h index 37ccd96e..1dc4079f 100644 --- a/contrib/curl/lib/hostip.h +++ b/contrib/curl/lib/hostip.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -50,7 +50,7 @@ struct addrinfo; struct hostent; -struct SessionHandle; +struct Curl_easy; struct connectdata; /* @@ -87,7 +87,7 @@ int Curl_resolv(struct connectdata *conn, const char *hostname, int port, struct Curl_dns_entry **dnsentry); int Curl_resolv_timeout(struct connectdata *conn, const char *hostname, int port, struct Curl_dns_entry **dnsentry, - long timeoutms); + time_t timeoutms); #ifdef CURLRES_IPV6 /* @@ -118,7 +118,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, /* unlock a previously resolved dns entry */ -void Curl_resolv_unlock(struct SessionHandle *data, +void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns); /* for debugging purposes only: */ @@ -128,10 +128,10 @@ void Curl_scan_cache_used(void *user, void *ptr); int Curl_mk_dnscache(struct curl_hash *hash); /* prune old entries from the DNS cache */ -void Curl_hostcache_prune(struct SessionHandle *data); +void Curl_hostcache_prune(struct Curl_easy *data); /* Return # of adresses in a Curl_addrinfo struct */ -int Curl_num_addresses (const Curl_addrinfo *addr); +int Curl_num_addresses(const Curl_addrinfo *addr); #if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa, @@ -143,7 +143,7 @@ int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa, #endif /* IPv4 threadsafe resolve function used for synch and asynch builds */ -Curl_addrinfo *Curl_ipv4_resolve_r(const char * hostname, int port); +Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port); CURLcode Curl_async_resolved(struct connectdata *conn, bool *protocol_connect); @@ -188,7 +188,7 @@ Curl_fetch_addr(struct connectdata *conn, * Returns the Curl_dns_entry entry pointer or NULL if the storage failed. */ struct Curl_dns_entry * -Curl_cache_addr(struct SessionHandle *data, Curl_addrinfo *addr, +Curl_cache_addr(struct Curl_easy *data, Curl_addrinfo *addr, const char *hostname, int port); #ifndef INADDR_NONE @@ -209,42 +209,42 @@ extern sigjmp_buf curl_jmpenv; /* * Function provided by the resolver backend to set DNS servers to use. */ -CURLcode Curl_set_dns_servers(struct SessionHandle *data, char *servers); +CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers); /* * Function provided by the resolver backend to set * outgoing interface to use for DNS requests */ -CURLcode Curl_set_dns_interface(struct SessionHandle *data, +CURLcode Curl_set_dns_interface(struct Curl_easy *data, const char *interf); /* * Function provided by the resolver backend to set * local IPv4 address to use as source address for DNS requests */ -CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, +CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, const char *local_ip4); /* * Function provided by the resolver backend to set * local IPv6 address to use as source address for DNS requests */ -CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data, +CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, const char *local_ip6); /* * Clean off entries from the cache */ -void Curl_hostcache_clean(struct SessionHandle *data, struct curl_hash *hash); +void Curl_hostcache_clean(struct Curl_easy *data, struct curl_hash *hash); /* * Destroy the hostcache of this handle. */ -void Curl_hostcache_destroy(struct SessionHandle *data); +void Curl_hostcache_destroy(struct Curl_easy *data); /* * Populate the cache with specified entries from CURLOPT_RESOLVE. */ -CURLcode Curl_loadhostpairs(struct SessionHandle *data); +CURLcode Curl_loadhostpairs(struct Curl_easy *data); #endif /* HEADER_CURL_HOSTIP_H */ diff --git a/contrib/curl/lib/hostip4.c b/contrib/curl/lib/hostip4.c index 15895d7c..e459328a 100644 --- a/contrib/curl/lib/hostip4.c +++ b/contrib/curl/lib/hostip4.c @@ -291,7 +291,7 @@ Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, * gethostbyname() is the preferred one. */ else { - h = gethostbyname((void*)hostname); + h = gethostbyname((void *)hostname); #endif /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */ } diff --git a/contrib/curl/lib/hostip6.c b/contrib/curl/lib/hostip6.c index 59bc4e4a..4ebfc2dc 100644 --- a/contrib/curl/lib/hostip6.c +++ b/contrib/curl/lib/hostip6.c @@ -167,10 +167,12 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, int error; char sbuf[12]; char *sbufptr = NULL; +#ifndef USE_RESOLVE_ON_IPS char addrbuf[128]; +#endif int pf; #if !defined(CURL_DISABLE_VERBOSE_STRINGS) - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; #endif *waitp = 0; /* synchronous response only */ @@ -196,11 +198,17 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, hints.ai_family = pf; hints.ai_socktype = conn->socktype; +#ifndef USE_RESOLVE_ON_IPS + /* + * The AI_NUMERICHOST must not be set to get synthesized IPv6 address from + * an IPv4 address on iOS and Mac OS X. + */ if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) || (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) { /* the given address is numerical only, prevent a reverse lookup */ hints.ai_flags = AI_NUMERICHOST; } +#endif if(port) { snprintf(sbuf, sizeof(sbuf), "%d", port); @@ -213,6 +221,10 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn, return NULL; } + if(port) { + Curl_addrinfo_set_port(res, port); + } + dump_addrinfo(conn, res); return res; diff --git a/contrib/curl/lib/hostsyn.c b/contrib/curl/lib/hostsyn.c index db4c82fc..1a95263c 100644 --- a/contrib/curl/lib/hostsyn.c +++ b/contrib/curl/lib/hostsyn.c @@ -59,7 +59,7 @@ /* * Function provided by the resolver backend to set DNS servers to use. */ -CURLcode Curl_set_dns_servers(struct SessionHandle *data, +CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers) { (void)data; @@ -72,7 +72,7 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data, * Function provided by the resolver backend to set * outgoing interface to use for DNS requests */ -CURLcode Curl_set_dns_interface(struct SessionHandle *data, +CURLcode Curl_set_dns_interface(struct Curl_easy *data, const char *interf) { (void)data; @@ -84,7 +84,7 @@ CURLcode Curl_set_dns_interface(struct SessionHandle *data, * Function provided by the resolver backend to set * local IPv4 address to use as source address for DNS requests */ -CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, +CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data, const char *local_ip4) { (void)data; @@ -96,7 +96,7 @@ CURLcode Curl_set_dns_local_ip4(struct SessionHandle *data, * Function provided by the resolver backend to set * local IPv6 address to use as source address for DNS requests */ -CURLcode Curl_set_dns_local_ip6(struct SessionHandle *data, +CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data, const char *local_ip6) { (void)data; diff --git a/contrib/curl/lib/http.c b/contrib/curl/lib/http.c index 6a76b88e..8db86cd8 100644 --- a/contrib/curl/lib/http.c +++ b/contrib/curl/lib/http.c @@ -53,7 +53,6 @@ #include "progress.h" #include "curl_base64.h" #include "cookie.h" -#include "strequal.h" #include "vauth/vauth.h" #include "vtls/vtls.h" #include "http_digest.h" @@ -68,7 +67,7 @@ #include "parsedate.h" /* for the week day and month names */ #include "strtoofft.h" #include "multiif.h" -#include "rawstr.h" +#include "strcase.h" #include "content_encoding.h" #include "http_proxy.h" #include "warnless.h" @@ -77,6 +76,7 @@ #include "pipeline.h" #include "http2.h" #include "connect.h" +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -151,7 +151,7 @@ const struct Curl_handler Curl_handler_https = { CURLcode Curl_http_setup_conn(struct connectdata *conn) { - /* allocate the HTTP-specific struct for the SessionHandle, only to survive + /* allocate the HTTP-specific struct for the Curl_easy, only to survive during this request */ struct HTTP *http; DEBUGASSERT(conn->data->req.protop == NULL); @@ -179,10 +179,10 @@ char *Curl_checkheaders(const struct connectdata *conn, { struct curl_slist *head; size_t thislen = strlen(thisheader); - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; for(head = data->set.headers;head; head=head->next) { - if(Curl_raw_nequal(head->data, thisheader, thislen)) + if(strncasecompare(head->data, thisheader, thislen)) return head->data; } @@ -194,7 +194,7 @@ char *Curl_checkheaders(const struct connectdata *conn, * if proxy headers are not available, then it will lookup into http header * link list * - * It takes a connectdata struct as input instead of the SessionHandle simply + * It takes a connectdata struct as input instead of the Curl_easy simply * to know if this is a proxy request or not, as it then might check a * different header list. */ @@ -203,12 +203,12 @@ char *Curl_checkProxyheaders(const struct connectdata *conn, { struct curl_slist *head; size_t thislen = strlen(thisheader); - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; for(head = (conn->bits.proxy && data->set.sep_headers) ? data->set.proxyheaders : data->set.headers; head; head=head->next) { - if(Curl_raw_nequal(head->data, thisheader, thislen)) + if(strncasecompare(head->data, thisheader, thislen)) return head->data; } @@ -280,7 +280,7 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) { size_t size = 0; char *authorization = NULL; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char **userp; const char *user; const char *pwd; @@ -288,8 +288,8 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) if(proxy) { userp = &conn->allocptr.proxyuserpwd; - user = conn->proxyuser; - pwd = conn->proxypasswd; + user = conn->http_proxy.user; + pwd = conn->http_proxy.passwd; } else { userp = &conn->allocptr.userpwd; @@ -297,7 +297,8 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) pwd = conn->passwd; } - snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd); + snprintf(data->state.buffer, CURL_BUFSIZE(data->set.buffer_size), + "%s:%s", user, pwd); result = Curl_base64_encode(data, data->state.buffer, strlen(data->state.buffer), @@ -377,7 +378,7 @@ static bool pickoneauth(struct auth *pick) */ static CURLcode http_perhapsrewind(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct HTTP *http = data->req.protop; curl_off_t bytessent; curl_off_t expectsend = -1; /* default is unknown */ @@ -462,7 +463,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) #endif /* This is not NTLM or many bytes left to send: close */ - connclose(conn, "Mid-auth HTTP and much data left to send"); + streamclose(conn, "Mid-auth HTTP and much data left to send"); data->req.size = 0; /* don't download any more than 0 bytes */ /* There still is data left to send, but this connection is marked for @@ -485,7 +486,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) CURLcode Curl_http_auth_act(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; bool pickhost = FALSE; bool pickproxy = FALSE; CURLcode result = CURLE_OK; @@ -545,8 +546,8 @@ CURLcode Curl_http_auth_act(struct connectdata *conn) } } if(http_should_fail(conn)) { - failf (data, "The requested URL returned error: %d", - data->req.httpcode); + failf(data, "The requested URL returned error: %d", + data->req.httpcode); result = CURLE_HTTP_RETURNED_ERROR; } @@ -567,7 +568,7 @@ output_auth_headers(struct connectdata *conn, const char *auth = NULL; CURLcode result = CURLE_OK; #if !defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_SPNEGO) - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; #endif #ifdef USE_SPNEGO struct negotiatedata *negdata = proxy ? @@ -642,7 +643,7 @@ output_auth_headers(struct connectdata *conn, if(auth) { infof(data, "%s auth using %s with user '%s'\n", proxy ? "Proxy" : "Server", auth, - proxy ? (conn->proxyuser ? conn->proxyuser : "") : + proxy ? (conn->http_proxy.user ? conn->http_proxy.user : "") : (conn->user ? conn->user : "")); authstatus->multi = (!authstatus->done) ? TRUE : FALSE; } @@ -674,7 +675,7 @@ Curl_http_output_auth(struct connectdata *conn, up the proxy tunnel */ { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct auth *authhost; struct auth *authproxy; @@ -726,7 +727,7 @@ Curl_http_output_auth(struct connectdata *conn, conn->bits.netrc || !data->state.first_host || data->set.http_disable_hostname_check_before_authentication || - Curl_raw_equal(data->state.first_host, conn->host.name)) { + strcasecompare(data->state.first_host, conn->host.name)) { result = output_auth_headers(conn, authhost, request, path, FALSE); } else @@ -747,7 +748,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, /* * This resource requires authentication */ - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; #ifdef USE_SPNEGO struct negotiatedata *negdata = proxy? @@ -784,23 +785,27 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, while(*auth) { #ifdef USE_SPNEGO if(checkprefix("Negotiate", auth)) { - *availp |= CURLAUTH_NEGOTIATE; - authp->avail |= CURLAUTH_NEGOTIATE; + if((authp->avail & CURLAUTH_NEGOTIATE) || + Curl_auth_is_spnego_supported()) { + *availp |= CURLAUTH_NEGOTIATE; + authp->avail |= CURLAUTH_NEGOTIATE; - if(authp->picked == CURLAUTH_NEGOTIATE) { - if(negdata->state == GSS_AUTHSENT || negdata->state == GSS_AUTHNONE) { - CURLcode result = Curl_input_negotiate(conn, proxy, auth); - if(!result) { - DEBUGASSERT(!data->req.newurl); - data->req.newurl = strdup(data->change.url); - if(!data->req.newurl) - return CURLE_OUT_OF_MEMORY; - data->state.authproblem = FALSE; - /* we received a GSS auth token and we dealt with it fine */ - negdata->state = GSS_AUTHRECV; + if(authp->picked == CURLAUTH_NEGOTIATE) { + if(negdata->state == GSS_AUTHSENT || + negdata->state == GSS_AUTHNONE) { + CURLcode result = Curl_input_negotiate(conn, proxy, auth); + if(!result) { + DEBUGASSERT(!data->req.newurl); + data->req.newurl = strdup(data->change.url); + if(!data->req.newurl) + return CURLE_OUT_OF_MEMORY; + data->state.authproblem = FALSE; + /* we received a GSS auth token and we dealt with it fine */ + negdata->state = GSS_AUTHRECV; + } + else + data->state.authproblem = TRUE; } - else - data->state.authproblem = TRUE; } } } @@ -809,39 +814,46 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, #ifdef USE_NTLM /* NTLM support requires the SSL crypto libs */ if(checkprefix("NTLM", auth)) { - *availp |= CURLAUTH_NTLM; - authp->avail |= CURLAUTH_NTLM; - if(authp->picked == CURLAUTH_NTLM || - authp->picked == CURLAUTH_NTLM_WB) { - /* NTLM authentication is picked and activated */ - CURLcode result = Curl_input_ntlm(conn, proxy, auth); - if(!result) { - data->state.authproblem = FALSE; -#ifdef NTLM_WB_ENABLED - if(authp->picked == CURLAUTH_NTLM_WB) { - *availp &= ~CURLAUTH_NTLM; - authp->avail &= ~CURLAUTH_NTLM; - *availp |= CURLAUTH_NTLM_WB; - authp->avail |= CURLAUTH_NTLM_WB; + if((authp->avail & CURLAUTH_NTLM) || + (authp->avail & CURLAUTH_NTLM_WB) || + Curl_auth_is_ntlm_supported()) { + *availp |= CURLAUTH_NTLM; + authp->avail |= CURLAUTH_NTLM; - /* Get the challenge-message which will be passed to - * ntlm_auth for generating the type 3 message later */ - while(*auth && ISSPACE(*auth)) - auth++; - if(checkprefix("NTLM", auth)) { - auth += strlen("NTLM"); + if(authp->picked == CURLAUTH_NTLM || + authp->picked == CURLAUTH_NTLM_WB) { + /* NTLM authentication is picked and activated */ + CURLcode result = Curl_input_ntlm(conn, proxy, auth); + if(!result) { + data->state.authproblem = FALSE; +#ifdef NTLM_WB_ENABLED + if(authp->picked == CURLAUTH_NTLM_WB) { + *availp &= ~CURLAUTH_NTLM; + authp->avail &= ~CURLAUTH_NTLM; + *availp |= CURLAUTH_NTLM_WB; + authp->avail |= CURLAUTH_NTLM_WB; + + /* Get the challenge-message which will be passed to + * ntlm_auth for generating the type 3 message later */ while(*auth && ISSPACE(*auth)) auth++; - if(*auth) - if((conn->challenge_header = strdup(auth)) == NULL) - return CURLE_OUT_OF_MEMORY; + if(checkprefix("NTLM", auth)) { + auth += strlen("NTLM"); + while(*auth && ISSPACE(*auth)) + auth++; + if(*auth) { + conn->challenge_header = strdup(auth); + if(!conn->challenge_header) + return CURLE_OUT_OF_MEMORY; + } + } } - } #endif - } - else { - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; + } + else { + infof(data, "Authentication problem. Ignoring this.\n"); + data->state.authproblem = TRUE; + } } } } @@ -849,18 +861,18 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, #endif #ifndef CURL_DISABLE_CRYPTO_AUTH if(checkprefix("Digest", auth)) { - if((authp->avail & CURLAUTH_DIGEST) != 0) { + if((authp->avail & CURLAUTH_DIGEST) != 0) infof(data, "Ignoring duplicate digest auth header.\n"); - } - else { + else if(Curl_auth_is_digest_supported()) { CURLcode result; + *availp |= CURLAUTH_DIGEST; authp->avail |= CURLAUTH_DIGEST; /* We call this function on input Digest headers even if Digest * authentication isn't activated yet, as we need to store the - * incoming data from this header in case we are gonna use - * Digest. */ + * incoming data from this header in case we are going to use + * Digest */ result = Curl_input_digest(conn, proxy, auth); if(result) { infof(data, "Authentication problem. Ignoring this.\n"); @@ -907,7 +919,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, */ static int http_should_fail(struct connectdata *conn) { - struct SessionHandle *data; + struct Curl_easy *data; int httpcode; DEBUGASSERT(conn); @@ -1090,7 +1102,9 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, return result; } - if((conn->handler->flags & PROTOPT_SSL) && conn->httpversion != 20) { + if((conn->handler->flags & PROTOPT_SSL || + conn->http_proxy.proxytype == CURLPROXY_HTTPS) + && conn->httpversion != 20) { /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk when we speak HTTPS, as if only a fraction of it is sent now, this data needs to fit into the normal read-callback buffer later on and that @@ -1247,14 +1261,13 @@ CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size) if(in->buffer) /* we have a buffer, enlarge the existing one */ - new_rb = realloc(in->buffer, new_size); + new_rb = Curl_saferealloc(in->buffer, new_size); else /* create a new buffer */ new_rb = malloc(new_size); if(!new_rb) { /* If we failed, we cleanup the whole buffer and return error */ - Curl_safefree(in->buffer); free(in); return CURLE_OUT_OF_MEMORY; } @@ -1296,7 +1309,7 @@ Curl_compareheader(const char *headerline, /* line to check */ const char *start; const char *end; - if(!Curl_raw_nequal(headerline, header, hlen)) + if(!strncasecompare(headerline, header, hlen)) return FALSE; /* doesn't start with header */ /* pass the header */ @@ -1322,7 +1335,7 @@ Curl_compareheader(const char *headerline, /* line to check */ /* find the content string in the rest of the line */ for(;len>=clen;len--, start++) { - if(Curl_raw_nequal(start, content, clen)) + if(strncasecompare(start, content, clen)) return TRUE; /* match! */ } @@ -1342,10 +1355,13 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done) connkeep(conn, "HTTP default"); /* the CONNECT procedure might not have been completed */ - result = Curl_proxy_connect(conn); + result = Curl_proxy_connect(conn, FIRSTSOCKET); if(result) return result; + if(CONNECT_FIRSTSOCKET_PROXY_SSL()) + return CURLE_OK; /* wait for HTTPS proxy SSL initialization to complete */ + if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) /* nothing else to do except wait right now - we're not done here. */ return CURLE_OK; @@ -1388,50 +1404,16 @@ static CURLcode https_connecting(struct connectdata *conn, bool *done) return result; } -#endif -#if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ - defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS) || \ - defined(USE_MBEDTLS) -/* This function is for OpenSSL, GnuTLS, darwinssl, schannel and polarssl only. - It should be made to query the generic SSL layer instead. */ static int https_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks) { - if(conn->handler->flags & PROTOPT_SSL) { - struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; - - if(!numsocks) - return GETSOCK_BLANK; - - if(connssl->connecting_state == ssl_connect_2_writing) { - /* write mode */ - socks[0] = conn->sock[FIRSTSOCKET]; - return GETSOCK_WRITESOCK(0); - } - else if(connssl->connecting_state == ssl_connect_2_reading) { - /* read mode */ - socks[0] = conn->sock[FIRSTSOCKET]; - return GETSOCK_READSOCK(0); - } - } - - return CURLE_OK; -} -#else -#ifdef USE_SSL -static int https_getsock(struct connectdata *conn, - curl_socket_t *socks, - int numsocks) -{ - (void)conn; - (void)socks; - (void)numsocks; + if(conn->handler->flags & PROTOPT_SSL) + return Curl_ssl_getsock(conn, socks, numsocks); return GETSOCK_BLANK; } #endif /* USE_SSL */ -#endif /* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL */ /* * Curl_http_done() gets called after a single HTTP request has been @@ -1441,11 +1423,8 @@ static int https_getsock(struct connectdata *conn, CURLcode Curl_http_done(struct connectdata *conn, CURLcode status, bool premature) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct HTTP *http = data->req.protop; -#ifdef USE_NGHTTP2 - struct http_conn *httpc = &conn->proto.httpc; -#endif Curl_unencode_cleanup(conn); @@ -1458,7 +1437,7 @@ CURLcode Curl_http_done(struct connectdata *conn, * Do not close CONNECT_ONLY connections. */ if((data->req.httpcode != 401) && (data->req.httpcode != 407) && !data->set.connect_only) - connclose(conn, "Negotiate transfer completed"); + streamclose(conn, "Negotiate transfer completed"); Curl_cleanup_negotiate(data); } #endif @@ -1475,27 +1454,7 @@ CURLcode Curl_http_done(struct connectdata *conn, http->send_buffer = NULL; /* clear the pointer */ } -#ifdef USE_NGHTTP2 - if(http->header_recvbuf) { - DEBUGF(infof(data, "free header_recvbuf!!\n")); - Curl_add_buffer_free(http->header_recvbuf); - http->header_recvbuf = NULL; /* clear the pointer */ - Curl_add_buffer_free(http->trailer_recvbuf); - http->trailer_recvbuf = NULL; /* clear the pointer */ - if(http->push_headers) { - /* if they weren't used and then freed before */ - for(; http->push_headers_used > 0; --http->push_headers_used) { - free(http->push_headers[http->push_headers_used - 1]); - } - free(http->push_headers); - http->push_headers = NULL; - } - } - if(http->stream_id) { - nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0); - http->stream_id = 0; - } -#endif + Curl_http2_done(conn, premature); if(HTTPREQ_POST_FORM == data->set.httpreq) { data->req.bytecount = http->readbytecount + http->writebytecount; @@ -1539,7 +1498,7 @@ CURLcode Curl_http_done(struct connectdata *conn, * - if any server previously contacted to handle this request only supports * 1.0. */ -static bool use_http_1_1plus(const struct SessionHandle *data, +static bool use_http_1_1plus(const struct Curl_easy *data, const struct connectdata *conn) { if((data->state.httpversion == 10) || (conn->httpversion == 10)) @@ -1551,8 +1510,22 @@ static bool use_http_1_1plus(const struct SessionHandle *data, (data->set.httpversion >= CURL_HTTP_VERSION_1_1)); } +static const char *get_http_string(const struct Curl_easy *data, + const struct connectdata *conn) +{ +#ifdef USE_NGHTTP2 + if(conn->proto.httpc.h2) + return "2"; +#endif + + if(use_http_1_1plus(data, conn)) + return "1.1"; + + return "1.0"; +} + /* check and possibly add an Expect: header */ -static CURLcode expect100(struct SessionHandle *data, +static CURLcode expect100(struct Curl_easy *data, struct connectdata *conn, Curl_send_buffer *req_buffer) { @@ -1595,7 +1568,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, struct curl_slist *h[2]; struct curl_slist *headers; int numlists=1; /* by default */ - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int i; enum proxy_use proxy; @@ -1660,6 +1633,10 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, Connection: */ checkprefix("Connection", headers->data)) ; + else if((conn->httpversion == 20) && + checkprefix("Transfer-Encoding:", headers->data)) + /* HTTP/2 doesn't support chunked requests */ + ; else { CURLcode result = Curl_add_bufferf(req_buffer, "%s\r\n", headers->data); @@ -1700,7 +1677,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, return CURLE_OK; } -CURLcode Curl_add_timecondition(struct SessionHandle *data, +CURLcode Curl_add_timecondition(struct Curl_easy *data, Curl_send_buffer *req_buffer) { const struct tm *tm; @@ -1758,13 +1735,13 @@ CURLcode Curl_add_timecondition(struct SessionHandle *data, } /* - * Curl_http() gets called from the generic Curl_do() function when a HTTP + * Curl_http() gets called from the generic multi_do() function when a HTTP * request is to be performed. This creates and sends a properly constructed * HTTP request. */ CURLcode Curl_http(struct connectdata *conn, bool *done) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result = CURLE_OK; struct HTTP *http; const char *ppath = data->state.path; @@ -1946,47 +1923,42 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } #endif - if(conn->httpversion == 20) - /* In HTTP2 forbids Transfer-Encoding: chunked */ - ptr = NULL; + ptr = Curl_checkheaders(conn, "Transfer-Encoding:"); + if(ptr) { + /* Some kind of TE is requested, check if 'chunked' is chosen */ + data->req.upload_chunky = + Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"); + } else { - ptr = Curl_checkheaders(conn, "Transfer-Encoding:"); - if(ptr) { - /* Some kind of TE is requested, check if 'chunked' is chosen */ - data->req.upload_chunky = - Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"); - } - else { - if((conn->handler->protocol&PROTO_FAMILY_HTTP) && - data->set.upload && - (data->state.infilesize == -1)) { - if(conn->bits.authneg) - /* don't enable chunked during auth neg */ - ; - else if(use_http_1_1plus(data, conn)) { - /* HTTP, upload, unknown file size and not HTTP 1.0 */ - data->req.upload_chunky = TRUE; - } - else { - failf(data, "Chunky upload is not supported by HTTP 1.0"); - return CURLE_UPLOAD_FAILED; - } + if((conn->handler->protocol&PROTO_FAMILY_HTTP) && + data->set.upload && + (data->state.infilesize == -1)) { + if(conn->bits.authneg) + /* don't enable chunked during auth neg */ + ; + else if(use_http_1_1plus(data, conn)) { + /* HTTP, upload, unknown file size and not HTTP 1.0 */ + data->req.upload_chunky = TRUE; } else { - /* else, no chunky upload */ - data->req.upload_chunky = FALSE; + failf(data, "Chunky upload is not supported by HTTP 1.0"); + return CURLE_UPLOAD_FAILED; } - - if(data->req.upload_chunky) - te = "Transfer-Encoding: chunked\r\n"; } + else { + /* else, no chunky upload */ + data->req.upload_chunky = FALSE; + } + + if(data->req.upload_chunky) + te = "Transfer-Encoding: chunked\r\n"; } Curl_safefree(conn->allocptr.host); ptr = Curl_checkheaders(conn, "Host:"); if(ptr && (!data->state.this_is_a_follow || - Curl_raw_equal(data->state.first_host, conn->host.name))) { + strcasecompare(data->state.first_host, conn->host.name))) { #if !defined(CURL_DISABLE_COOKIES) /* If we have a given custom Host: header, we extract the host name in order to possibly use it for cookie reasons later on. We only allow the @@ -2106,7 +2078,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* when doing ftp, append ;type= if not present */ char *type = strstr(ppath, ";type="); if(type && type[6] && type[7] == 0) { - switch (Curl_raw_toupper(type[6])) { + switch(Curl_raw_toupper(type[6])) { case 'A': case 'D': case 'I': @@ -2266,9 +2238,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } } - /* Use 1.1 unless the user specifically asked for 1.0 or the server only - supports 1.0 */ - httpstring= use_http_1_1plus(data, conn)?"1.1":"1.0"; + httpstring = get_http_string(data, conn); /* initialize a dynamic send-buffer */ req_buffer = Curl_add_buffer_init(); @@ -2305,6 +2275,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) "%s" /* TE: */ "%s" /* accept-encoding */ "%s" /* referer */ + "%s" /* Proxy-Connection */ "%s",/* transfer-encoding */ ftp_typecode, @@ -2327,6 +2298,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->allocptr.accept_encoding:"", (data->change.referer && conn->allocptr.ref)? conn->allocptr.ref:"" /* Referer: */, + (conn->bits.httpproxy && + !conn->bits.tunnel_proxy && + !Curl_checkProxyheaders(conn, "Proxy-Connection:"))? + "Proxy-Connection: Keep-Alive\r\n":"", te ); @@ -2337,7 +2312,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) * Free proxyuserpwd for Negotiate/NTLM. Cannot reuse as it is associated * with the connection and shouldn't be repeated over it either. */ - switch (data->state.authproxy.picked) { + switch(data->state.authproxy.picked) { case CURLAUTH_NEGOTIATE: case CURLAUTH_NTLM: case CURLAUTH_NTLM_WB: @@ -2392,7 +2367,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } co = co->next; /* next cookie please */ } - Curl_cookie_freelist(store, FALSE); /* free the cookie list */ + Curl_cookie_freelist(store); } if(addcookies && !result) { if(!count) @@ -2537,7 +2512,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) postsize = data->state.infilesize; if((postsize != -1) && !data->req.upload_chunky && - !Curl_checkheaders(conn, "Content-Length:")) { + (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) { /* only add Content-Length if not uploading chunked */ result = Curl_add_bufferf(req_buffer, "Content-Length: %" CURL_FORMAT_CURL_OFF_T @@ -2589,7 +2564,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) we don't upload data chunked, as RFC2616 forbids us to set both kinds of headers (Transfer-Encoding: chunked and Content-Length) */ if((postsize != -1) && !data->req.upload_chunky && - !Curl_checkheaders(conn, "Content-Length:")) { + (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) { /* we allow replacing this header if not during auth negotiation, although it isn't very wise to actually set your own */ result = Curl_add_bufferf(req_buffer, @@ -2768,6 +2743,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } } + if((conn->httpversion == 20) && data->req.upload_chunky) + /* upload_chunky was set above to set up the request in a chunky fashion, + but is disabled here again to avoid that the chunked encoded version is + actually used when sending the request body over h2 */ + data->req.upload_chunky = FALSE; return result; } @@ -2777,7 +2757,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) * Returns TRUE if member of the list matches prefix of string */ static bool -checkhttpprefix(struct SessionHandle *data, +checkhttpprefix(struct Curl_easy *data, const char *s) { struct curl_slist *head = data->set.http200aliases; @@ -2786,7 +2766,7 @@ checkhttpprefix(struct SessionHandle *data, /* convert from the network encoding using a scratch area */ char *scratch = strdup(s); if(NULL == scratch) { - failf (data, "Failed to allocate memory for conversion!"); + failf(data, "Failed to allocate memory for conversion!"); return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ } if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) { @@ -2816,7 +2796,7 @@ checkhttpprefix(struct SessionHandle *data, #ifndef CURL_DISABLE_RTSP static bool -checkrtspprefix(struct SessionHandle *data, +checkrtspprefix(struct Curl_easy *data, const char *s) { @@ -2824,7 +2804,7 @@ checkrtspprefix(struct SessionHandle *data, /* convert from the network encoding using a scratch area */ char *scratch = strdup(s); if(NULL == scratch) { - failf (data, "Failed to allocate memory for conversion!"); + failf(data, "Failed to allocate memory for conversion!"); return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ } if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) { @@ -2844,7 +2824,7 @@ checkrtspprefix(struct SessionHandle *data, #endif /* CURL_DISABLE_RTSP */ static bool -checkprotoprefix(struct SessionHandle *data, struct connectdata *conn, +checkprotoprefix(struct Curl_easy *data, struct connectdata *conn, const char *s) { #ifndef CURL_DISABLE_RTSP @@ -2862,7 +2842,7 @@ checkprotoprefix(struct SessionHandle *data, struct connectdata *conn, * header. We make sure that the full string fit in the allocated header * buffer, or else we enlarge it. */ -static CURLcode header_append(struct SessionHandle *data, +static CURLcode header_append(struct Curl_easy *data, struct SingleRequest *k, size_t length) { @@ -2876,8 +2856,8 @@ static CURLcode header_append(struct SessionHandle *data, /* The reason to have a max limit for this is to avoid the risk of a bad server feeding libcurl with a never-ending header that will cause reallocs infinitely */ - failf (data, "Avoided giant realloc for header (max is %d)!", - CURL_MAX_HTTP_HEADER); + failf(data, "Avoided giant realloc for header (max is %d)!", + CURL_MAX_HTTP_HEADER); return CURLE_OUT_OF_MEMORY; } @@ -2885,7 +2865,7 @@ static CURLcode header_append(struct SessionHandle *data, hbufp_index = k->hbufp - data->state.headerbuff; newbuff = realloc(data->state.headerbuff, newsize); if(!newbuff) { - failf (data, "Failed to alloc memory for big header!"); + failf(data, "Failed to alloc memory for big header!"); return CURLE_OUT_OF_MEMORY; } data->state.headersize=newsize; @@ -2900,7 +2880,7 @@ static CURLcode header_append(struct SessionHandle *data, return CURLE_OK; } -static void print_http_error(struct SessionHandle *data) +static void print_http_error(struct Curl_easy *data) { struct SingleRequest *k = &data->req; char *beg = k->p; @@ -2940,7 +2920,7 @@ static void print_http_error(struct SessionHandle *data) /* * Read any HTTP header lines from the server and pass them to the client app. */ -CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, +CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, bool *stop_reading) @@ -3040,21 +3020,21 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, #endif /* CURL_DOES_CONVERSIONS */ if(100 <= k->httpcode && 199 >= k->httpcode) { - /* - * We have made a HTTP PUT or POST and this is 1.1-lingo - * that tells us that the server is OK with this and ready - * to receive the data. - * However, we'll get more headers now so we must get - * back into the header-parsing state! - */ - k->header = TRUE; - k->headerline = 0; /* restart the header line counter */ - /* "A user agent MAY ignore unexpected 1xx status responses." */ switch(k->httpcode) { case 100: + /* + * We have made a HTTP PUT or POST and this is 1.1-lingo + * that tells us that the server is OK with this and ready + * to receive the data. + * However, we'll get more headers now so we must get + * back into the header-parsing state! + */ + k->header = TRUE; + k->headerline = 0; /* restart the header line counter */ + /* if we did wait for this do enable write now! */ - if(k->exp100) { + if(k->exp100 > EXP100_SEND_DATA) { k->exp100 = EXP100_SEND_DATA; k->keepon |= KEEP_SEND; } @@ -3062,9 +3042,14 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, case 101: /* Switching Protocols */ if(k->upgr101 == UPGR101_REQUESTED) { + /* Switching to HTTP/2 */ infof(data, "Received 101\n"); k->upgr101 = UPGR101_RECEIVED; + /* we'll get more headers (HTTP/2 response) */ + k->header = TRUE; + k->headerline = 0; /* restart the header line counter */ + /* switch to http2 now. The bytes after response headers are also processed here, otherwise they are lost. */ result = Curl_http2_switched(conn, k->str, *nread); @@ -3072,8 +3057,16 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, return result; *nread = 0; } + else { + /* Switching to another protocol (e.g. WebSocket) */ + k->header = FALSE; /* no more header to parse! */ + } break; default: + /* the status code 1xx indicates a provisional response, so + we'll get another set of headers */ + k->header = TRUE; + k->headerline = 0; /* restart the header line counter */ break; } } @@ -3091,7 +3084,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, signal the end of the document. */ infof(data, "no chunk, no close, no size. Assume close to " "signal end\n"); - connclose(conn, "HTTP: No end-of-message indicator"); + streamclose(conn, "HTTP: No end-of-message indicator"); } } @@ -3113,8 +3106,8 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, * up and return an error. */ if(http_should_fail(conn)) { - failf (data, "The requested URL returned error: %d", - k->httpcode); + failf(data, "The requested URL returned error: %d", + k->httpcode); return CURLE_HTTP_RETURNED_ERROR; } @@ -3138,52 +3131,59 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, data->req.deductheadercount = (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0; - if(!*stop_reading) { - /* Curl_http_auth_act() checks what authentication methods - * that are available and decides which one (if any) to - * use. It will set 'newurl' if an auth method was picked. */ - result = Curl_http_auth_act(conn); + /* Curl_http_auth_act() checks what authentication methods + * that are available and decides which one (if any) to + * use. It will set 'newurl' if an auth method was picked. */ + result = Curl_http_auth_act(conn); - if(result) - return result; + if(result) + return result; - if(k->httpcode >= 300) { - if((!conn->bits.authneg) && !conn->bits.close && - !conn->bits.rewindaftersend) { - /* - * General treatment of errors when about to send data. Including : - * "417 Expectation Failed", while waiting for 100-continue. - * - * The check for close above is done simply because of something - * else has already deemed the connection to get closed then - * something else should've considered the big picture and we - * avoid this check. - * - * rewindaftersend indicates that something has told libcurl to - * continue sending even if it gets discarded + if(k->httpcode >= 300) { + if((!conn->bits.authneg) && !conn->bits.close && + !conn->bits.rewindaftersend) { + /* + * General treatment of errors when about to send data. Including : + * "417 Expectation Failed", while waiting for 100-continue. + * + * The check for close above is done simply because of something + * else has already deemed the connection to get closed then + * something else should've considered the big picture and we + * avoid this check. + * + * rewindaftersend indicates that something has told libcurl to + * continue sending even if it gets discarded + */ + + switch(data->set.httpreq) { + case HTTPREQ_PUT: + case HTTPREQ_POST: + case HTTPREQ_POST_FORM: + /* We got an error response. If this happened before the whole + * request body has been sent we stop sending and mark the + * connection for closure after we've read the entire response. */ - - switch(data->set.httpreq) { - case HTTPREQ_PUT: - case HTTPREQ_POST: - case HTTPREQ_POST_FORM: - /* We got an error response. If this happened before the whole - * request body has been sent we stop sending and mark the - * connection for closure after we've read the entire response. - */ - if(!k->upload_done) { + if(!k->upload_done) { + if(data->set.http_keep_sending_on_error) { + infof(data, "HTTP error before end of send, keep sending\n"); + if(k->exp100 > EXP100_SEND_DATA) { + k->exp100 = EXP100_SEND_DATA; + k->keepon |= KEEP_SEND; + } + } + else { infof(data, "HTTP error before end of send, stop sending\n"); - connclose(conn, "Stop sending data before everything sent"); + streamclose(conn, "Stop sending data before everything sent"); k->upload_done = TRUE; k->keepon &= ~KEEP_SEND; /* don't send */ if(data->state.expect100header) k->exp100 = EXP100_FAILED; } - break; - - default: /* default label present to avoid compiler warnings */ - break; } + break; + + default: /* default label present to avoid compiler warnings */ + break; } } @@ -3210,7 +3210,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, (k->size <= -1)) /* Respect section 4.4 of rfc2326: If the Content-Length header is absent, a length 0 must be assumed. It will prevent libcurl from - hanging on DECRIBE request that got refused for whatever + hanging on DESCRIBE request that got refused for whatever reason */ *stop_reading = TRUE; #endif @@ -3308,6 +3308,13 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, &httpversion_major, &conn->httpversion, &k->httpcode); + + if(nc == 1 && httpversion_major == 2 && + 1 == sscanf(HEADER1, " HTTP/2 %d", &k->httpcode)) { + conn->httpversion = 0; + nc = 3; + } + if(nc==3) { conn->httpversion += 10 * httpversion_major; @@ -3471,7 +3478,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, /* Negative Content-Length is really odd, and we know it happens for example when older Apache servers send large files */ - connclose(conn, "negative content-length"); + streamclose(conn, "negative content-length"); infof(data, "Negative content-length: %" CURL_FORMAT_CURL_OFF_T ", closing after transfer\n", contentlength); } @@ -3544,7 +3551,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, * the connection will close when this request has been * served. */ - connclose(conn, "Connection: close used"); + streamclose(conn, "Connection: close used"); } else if(checkprefix("Transfer-Encoding:", k->p)) { /* One or more encodings. We check for chunked and/or a compression @@ -3754,7 +3761,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, k->hbufp = data->state.headerbuff; k->hbuflen = 0; } - while(!*stop_reading && *k->str); /* header line within buffer */ + while(*k->str); /* header line within buffer */ /* We might have reached the end of the header part here, but there might be a non-header part left in the end of the read diff --git a/contrib/curl/lib/http.h b/contrib/curl/lib/http.h index 981472e0..7ce4bd9a 100644 --- a/contrib/curl/lib/http.h +++ b/contrib/curl/lib/http.h @@ -69,7 +69,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, size_t included_body_bytes, int socketindex); -CURLcode Curl_add_timecondition(struct SessionHandle *data, +CURLcode Curl_add_timecondition(struct Curl_easy *data, Curl_send_buffer *buf); CURLcode Curl_add_custom_headers(struct connectdata *conn, bool is_connect, @@ -87,7 +87,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap, ssize_t length, ssize_t *wrote); /* These functions are in http.c */ -void Curl_http_auth_stage(struct SessionHandle *data, int stage); +void Curl_http_auth_stage(struct Curl_easy *data, int stage); CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy, const char *auth); CURLcode Curl_http_auth_act(struct connectdata *conn); @@ -168,6 +168,7 @@ struct HTTP { const uint8_t *pausedata; /* pointer to data received in on_data_chunk */ size_t pauselen; /* the number of bytes left in data */ bool closed; /* TRUE on HTTP2 stream close */ + bool close_handled; /* TRUE if stream closure is handled by libcurl */ uint32_t error_code; /* HTTP/2 error code */ char *mem; /* points to a buffer in memory to store received data */ @@ -216,14 +217,18 @@ struct http_conn { nghttp2_session_mem_recv */ size_t drain_total; /* sum of all stream's UrlState.drain */ - /* this is a hash of all individual streams (SessionHandle structs) */ + /* this is a hash of all individual streams (Curl_easy structs) */ struct h2settings settings; + + /* list of settings that will be sent */ + nghttp2_settings_entry local_settings[3]; + size_t local_settings_num; #else int unused; /* prevent a compiler warning */ #endif }; -CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, +CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, bool *stop_reading); diff --git a/contrib/curl/lib/http2.c b/contrib/curl/lib/http2.c index 3fe02a57..af69c722 100644 --- a/contrib/curl/lib/http2.c +++ b/contrib/curl/lib/http2.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -29,13 +29,13 @@ #include "http.h" #include "sendf.h" #include "curl_base64.h" -#include "rawstr.h" +#include "strcase.h" #include "multiif.h" #include "conncache.h" #include "url.h" #include "connect.h" #include "strtoofft.h" - +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -59,6 +59,12 @@ #define nghttp2_session_callbacks_set_error_callback(x,y) #endif +#if (NGHTTP2_VERSION_NUM >= 0x010c00) +#define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1 +#endif + +#define HTTP2_HUGE_WINDOW_SIZE (1 << 30) + /* * Curl_http2_init_state() is called when the easy handle is created and * allows for HTTP/2 specific init of state. @@ -92,8 +98,9 @@ static int http2_perform_getsock(const struct connectdata *conn, because of renegotiation. */ sock[0] = conn->sock[FIRSTSOCKET]; - if(nghttp2_session_want_read(c->h2)) - bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); + /* in a HTTP/2 connection we can basically always get a frame so we should + always be ready for one */ + bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); if(nghttp2_session_want_write(c->h2)) bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); @@ -109,18 +116,11 @@ static int http2_getsock(struct connectdata *conn, return http2_perform_getsock(conn, sock, numsocks); } -static CURLcode http2_disconnect(struct connectdata *conn, - bool dead_connection) +/* + * http2_stream_free() free HTTP2 stream related data + */ +static void http2_stream_free(struct HTTP *http) { - struct HTTP *http = conn->data->req.protop; - struct http_conn *c = &conn->proto.httpc; - (void)dead_connection; - - DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n")); - - nghttp2_session_del(c->h2); - Curl_safefree(c->inbuf); - if(http) { Curl_add_buffer_free(http->header_recvbuf); http->header_recvbuf = NULL; /* clear the pointer */ @@ -132,6 +132,19 @@ static CURLcode http2_disconnect(struct connectdata *conn, free(http->push_headers); http->push_headers = NULL; } +} + +static CURLcode http2_disconnect(struct connectdata *conn, + bool dead_connection) +{ + struct http_conn *c = &conn->proto.httpc; + (void)dead_connection; + + DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n")); + + nghttp2_session_del(c->h2); + Curl_safefree(c->inbuf); + http2_stream_free(conn->data->req.protop); DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n")); @@ -139,7 +152,7 @@ static CURLcode http2_disconnect(struct connectdata *conn, } /* called from Curl_http_setup_conn */ -void Curl_http2_setup_req(struct SessionHandle *data) +void Curl_http2_setup_req(struct Curl_easy *data) { struct HTTP *http = data->req.protop; @@ -150,6 +163,7 @@ void Curl_http2_setup_req(struct SessionHandle *data) http->pauselen = 0; http->error_code = NGHTTP2_NO_ERROR; http->closed = FALSE; + http->close_handled = FALSE; http->mem = data->state.buffer; http->len = BUFSIZE; http->memlen = 0; @@ -184,7 +198,7 @@ const struct Curl_handler Curl_handler_http2 = { ZERO_NULL, /* readwrite */ PORT_HTTP, /* defport */ CURLPROTO_HTTP, /* protocol */ - PROTOPT_NONE /* flags */ + PROTOPT_STREAM /* flags */ }; const struct Curl_handler Curl_handler_http2_ssl = { @@ -204,7 +218,7 @@ const struct Curl_handler Curl_handler_http2_ssl = { ZERO_NULL, /* readwrite */ PORT_HTTP, /* defport */ CURLPROTO_HTTPS, /* protocol */ - PROTOPT_SSL /* flags */ + PROTOPT_SSL | PROTOPT_STREAM /* flags */ }; /* @@ -221,7 +235,8 @@ int Curl_http2_ver(char *p, size_t len) https://tools.ietf.org/html/rfc7540#page-77 nghttp2_error_code enums are identical. */ -const char *Curl_http2_strerror(uint32_t err) { +const char *Curl_http2_strerror(uint32_t err) +{ #ifndef NGHTTP2_HAS_HTTP2_STRERROR const char *str[] = { "NO_ERROR", /* 0x0 */ @@ -284,7 +299,7 @@ static ssize_t send_callback(nghttp2_session *h2, /* We pass a pointer to this struct in the push callback, but the contents of the struct are hidden from the user. */ struct curl_pushheaders { - struct SessionHandle *data; + struct Curl_easy *data; const nghttp2_push_promise *frame; }; @@ -317,7 +332,7 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) the middle of header, it could be matched in middle of the value, this is because we do prefix match.*/ if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] || - Curl_raw_equal(header, ":") || strchr(header + 1, ':')) + !strcmp(header, ":") || strchr(header + 1, ':')) return NULL; else { struct HTTP *stream = h->data->req.protop; @@ -335,9 +350,9 @@ char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) return NULL; } -static CURL *duphandle(struct SessionHandle *data) +static struct Curl_easy *duphandle(struct Curl_easy *data) { - struct SessionHandle *second = curl_easy_duphandle(data); + struct Curl_easy *second = curl_easy_duphandle(data); if(second) { /* setup the request struct */ struct HTTP *http = calloc(1, sizeof(struct HTTP)); @@ -363,7 +378,7 @@ static CURL *duphandle(struct SessionHandle *data) } -static int push_promise(struct SessionHandle *data, +static int push_promise(struct Curl_easy *data, struct connectdata *conn, const nghttp2_push_promise *frame) { @@ -378,7 +393,7 @@ static int push_promise(struct SessionHandle *data, struct http_conn *httpc; size_t i; /* clone the parent */ - struct SessionHandle *newhandle = duphandle(data); + struct Curl_easy *newhandle = duphandle(data); if(!newhandle) { infof(data, "failed to duplicate handle\n"); rv = 1; /* FAIL HARD */ @@ -406,9 +421,11 @@ static int push_promise(struct SessionHandle *data, free(stream->push_headers[i]); free(stream->push_headers); stream->push_headers = NULL; + stream->push_headers_used = 0; if(rv) { /* denied, kill off the new handle again */ + http2_stream_free(newhandle->req.protop); (void)Curl_close(newhandle); goto fail; } @@ -423,6 +440,7 @@ static int push_promise(struct SessionHandle *data, rc = Curl_multi_add_perform(data->multi, newhandle, conn); if(rc) { infof(data, "failed to add handle to multi\n"); + http2_stream_free(newhandle->req.protop); Curl_close(newhandle); rv = 1; goto fail; @@ -445,7 +463,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, { struct connectdata *conn = (struct connectdata *)userp; struct http_conn *httpc = &conn->proto.httpc; - struct SessionHandle *data_s = NULL; + struct Curl_easy *data_s = NULL; struct HTTP *stream = NULL; static int lastStream = -1; int rv; @@ -482,14 +500,17 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, } if(!data_s) { DEBUGF(infof(conn->data, - "No SessionHandle associated with stream: %x\n", + "No Curl_easy associated with stream: %x\n", stream_id)); return 0; } stream = data_s->req.protop; - if(!stream) + if(!stream) { + DEBUGF(infof(conn->data, "No proto pointer for stream: %x\n", + stream_id)); return NGHTTP2_ERR_CALLBACK_FAILURE; + } DEBUGF(infof(data_s, "on_frame_recv() header %x stream %x\n", frame->hd.type, stream_id)); @@ -547,7 +568,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, /* if we receive data for another handle, wake that up */ if(conn_s->data != data_s) - Curl_expire(data_s, 1); + Curl_expire(data_s, 0); } break; case NGHTTP2_PUSH_PROMISE: @@ -573,7 +594,7 @@ static int on_invalid_frame_recv(nghttp2_session *session, const nghttp2_frame *frame, int lib_error_code, void *userp) { - struct SessionHandle *data_s = NULL; + struct Curl_easy *data_s = NULL; (void)userp; data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); @@ -590,7 +611,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, const uint8_t *data, size_t len, void *userp) { struct HTTP *stream; - struct SessionHandle *data_s; + struct Curl_easy *data_s; size_t nread; struct connectdata *conn = (struct connectdata *)userp; (void)session; @@ -621,8 +642,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags, /* if we receive data for another handle, wake that up */ if(conn->data != data_s) - Curl_expire(data_s, 1); /* TODO: fix so that this can be set to 0 for - immediately? */ + Curl_expire(data_s, 0); DEBUGF(infof(data_s, "%zu data received for stream %u " "(%zu left in buffer %p, total %zu)\n", @@ -656,7 +676,7 @@ static int before_frame_send(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { - struct SessionHandle *data_s; + struct Curl_easy *data_s; (void)userp; data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); @@ -670,7 +690,7 @@ static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { - struct SessionHandle *data_s; + struct Curl_easy *data_s; (void)userp; data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); @@ -684,7 +704,7 @@ static int on_frame_not_send(nghttp2_session *session, const nghttp2_frame *frame, int lib_error_code, void *userp) { - struct SessionHandle *data_s; + struct Curl_easy *data_s; (void)userp; data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); @@ -698,7 +718,7 @@ static int on_frame_not_send(nghttp2_session *session, static int on_stream_close(nghttp2_session *session, int32_t stream_id, uint32_t error_code, void *userp) { - struct SessionHandle *data_s; + struct Curl_easy *data_s; struct HTTP *stream; struct connectdata *conn = (struct connectdata *)userp; (void)session; @@ -735,7 +755,7 @@ static int on_begin_headers(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { struct HTTP *stream; - struct SessionHandle *data_s = NULL; + struct Curl_easy *data_s = NULL; (void)userp; data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); @@ -802,7 +822,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, void *userp) { struct HTTP *stream; - struct SessionHandle *data_s; + struct Curl_easy *data_s; int32_t stream_id = frame->hd.stream_id; struct connectdata *conn = (struct connectdata *)userp; (void)flags; @@ -837,10 +857,9 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, stream->push_headers_alloc) { char **headp; stream->push_headers_alloc *= 2; - headp = realloc(stream->push_headers, - stream->push_headers_alloc * sizeof(char *)); + headp = Curl_saferealloc(stream->push_headers, + stream->push_headers_alloc * sizeof(char *)); if(!headp) { - free(stream->push_headers); stream->push_headers = NULL; return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; } @@ -883,7 +902,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, Curl_add_buffer(stream->header_recvbuf, " \r\n", 3); /* if we receive data for another handle, wake that up */ if(conn->data != data_s) - Curl_expire(data_s, 1); + Curl_expire(data_s, 0); DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n", stream->status_code, data_s)); @@ -899,7 +918,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, Curl_add_buffer(stream->header_recvbuf, "\r\n", 2); /* if we receive data for another handle, wake that up */ if(conn->data != data_s) - Curl_expire(data_s, 1); + Curl_expire(data_s, 0); DEBUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen, value)); @@ -914,7 +933,7 @@ static ssize_t data_source_read_callback(nghttp2_session *session, nghttp2_data_source *source, void *userp) { - struct SessionHandle *data_s; + struct Curl_easy *data_s; struct HTTP *stream = NULL; size_t nread; (void)source; @@ -941,11 +960,12 @@ static ssize_t data_source_read_callback(nghttp2_session *session, memcpy(buf, stream->upload_mem, nread); stream->upload_mem += nread; stream->upload_len -= nread; - stream->upload_left -= nread; + if(data_s->state.infilesize != -1) + stream->upload_left -= nread; } if(stream->upload_left == 0) - *data_flags = 1; + *data_flags = NGHTTP2_DATA_FLAG_EOF; else if(nread == 0) return NGHTTP2_ERR_DEFERRED; @@ -956,14 +976,6 @@ static ssize_t data_source_read_callback(nghttp2_session *session, return nread; } -/* - * The HTTP2 settings we send in the Upgrade request - */ -static nghttp2_settings_entry settings[] = { - { NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 }, - { NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, NGHTTP2_INITIAL_WINDOW_SIZE }, -}; - #define H2_BUFSIZE 32768 #ifdef NGHTTP2_HAS_ERROR_CALLBACK @@ -979,6 +991,60 @@ static int error_callback(nghttp2_session *session, } #endif +static void populate_settings(struct connectdata *conn, + struct http_conn *httpc) +{ + nghttp2_settings_entry *iv = httpc->local_settings; + + iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS; + iv[0].value = 100; + + iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE; + iv[1].value = HTTP2_HUGE_WINDOW_SIZE; + + iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH; + iv[2].value = conn->data->multi->push_cb != NULL; + + httpc->local_settings_num = 3; +} + +void Curl_http2_done(struct connectdata *conn, bool premature) +{ + struct Curl_easy *data = conn->data; + struct HTTP *http = data->req.protop; + struct http_conn *httpc = &conn->proto.httpc; + + if(http->header_recvbuf) { + DEBUGF(infof(data, "free header_recvbuf!!\n")); + Curl_add_buffer_free(http->header_recvbuf); + http->header_recvbuf = NULL; /* clear the pointer */ + Curl_add_buffer_free(http->trailer_recvbuf); + http->trailer_recvbuf = NULL; /* clear the pointer */ + if(http->push_headers) { + /* if they weren't used and then freed before */ + for(; http->push_headers_used > 0; --http->push_headers_used) { + free(http->push_headers[http->push_headers_used - 1]); + } + free(http->push_headers); + http->push_headers = NULL; + } + } + + if(premature) { + /* RST_STREAM */ + nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE, http->stream_id, + NGHTTP2_STREAM_CLOSED); + if(http->stream_id == httpc->pause_stream_id) { + infof(data, "stopped the pause stream!\n"); + httpc->pause_stream_id = 0; + } + } + if(http->stream_id) { + nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0); + http->stream_id = 0; + } +} + /* * Initialize nghttp2 for a Curl connection */ @@ -1055,16 +1121,14 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, size_t blen; struct SingleRequest *k = &conn->data->req; uint8_t *binsettings = conn->proto.httpc.binsettings; + struct http_conn *httpc = &conn->proto.httpc; - /* As long as we have a fixed set of settings, we don't have to dynamically - * figure out the base64 strings since it'll always be the same. However, - * the settings will likely not be fixed every time in the future. - */ + populate_settings(conn, httpc); /* this returns number of bytes it wrote */ binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN, - settings, - sizeof(settings)/sizeof(settings[0])); + httpc->local_settings, + httpc->local_settings_num); if(!binlen) { failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload"); return CURLE_FAILED_INIT; @@ -1091,12 +1155,13 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req, /* * Returns nonzero if current HTTP/2 session should be closed. */ -static int should_close_session(struct http_conn *httpc) { +static int should_close_session(struct http_conn *httpc) +{ return httpc->drain_total == 0 && !nghttp2_session_want_read(httpc->h2) && - !nghttp2_session_want_write(httpc->h2); + !nghttp2_session_want_write(httpc->h2); } -static int h2_session_send(struct SessionHandle *data, +static int h2_session_send(struct Curl_easy *data, nghttp2_session *h2); /* @@ -1105,9 +1170,10 @@ static int h2_session_send(struct SessionHandle *data, * This function returns 0 if it succeeds, or -1 and error code will * be assigned to *err. */ -static int h2_process_pending_input(struct SessionHandle *data, +static int h2_process_pending_input(struct Curl_easy *data, struct http_conn *httpc, - CURLcode *err) { + CURLcode *err) +{ ssize_t nread; char *inbuf; ssize_t rv; @@ -1155,9 +1221,41 @@ static int h2_process_pending_input(struct SessionHandle *data, return 0; } +/* + * Called from transfer.c:done_sending when we stop uploading. + */ +CURLcode Curl_http2_done_sending(struct connectdata *conn) +{ + CURLcode result = CURLE_OK; + + if((conn->handler == &Curl_handler_http2_ssl) || + (conn->handler == &Curl_handler_http2)) { + /* make sure this is only attempted for HTTP/2 transfers */ + + struct HTTP *stream = conn->data->req.protop; + + if(stream->upload_left) { + /* If the stream still thinks there's data left to upload. */ + struct http_conn *httpc = &conn->proto.httpc; + nghttp2_session *h2 = httpc->h2; + + stream->upload_left = 0; /* DONE! */ + + /* resume sending here to trigger the callback to get called again so + that it can signal EOF to nghttp2 */ + (void)nghttp2_session_resume_data(h2, stream->stream_id); + + (void)h2_process_pending_input(conn->data, httpc, &result); + } + } + return result; +} + + static ssize_t http2_handle_stream_close(struct connectdata *conn, - struct SessionHandle *data, - struct HTTP *stream, CURLcode *err) { + struct Curl_easy *data, + struct HTTP *stream, CURLcode *err) +{ char *trailer_pos, *trailer_end; CURLcode result; struct http_conn *httpc = &conn->proto.httpc; @@ -1178,8 +1276,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, DEBUGASSERT(data->state.drain == 0); - /* Reset to FALSE to prevent infinite loop in readwrite_data - function. */ + /* Reset to FALSE to prevent infinite loop in readwrite_data function. */ stream->closed = FALSE; if(stream->error_code != NGHTTP2_NO_ERROR) { failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %d)", @@ -1216,6 +1313,8 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, } } + stream->close_handled = TRUE; + DEBUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n")); return 0; } @@ -1226,7 +1325,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn, * struct. */ -static void h2_pri_spec(struct SessionHandle *data, +static void h2_pri_spec(struct Curl_easy *data, nghttp2_priority_spec *pri_spec) { struct HTTP *depstream = (data->set.stream_depends_on? @@ -1244,7 +1343,7 @@ static void h2_pri_spec(struct SessionHandle *data, * dependency settings and if so it submits a PRIORITY frame with the updated * info. */ -static int h2_session_send(struct SessionHandle *data, +static int h2_session_send(struct Curl_easy *data, nghttp2_session *h2) { struct HTTP *stream = data->req.protop; @@ -1268,10 +1367,6 @@ static int h2_session_send(struct SessionHandle *data, return nghttp2_session_send(h2); } -/* - * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return - * a regular CURLcode value. - */ static ssize_t http2_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err) { @@ -1279,7 +1374,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, ssize_t rv; ssize_t nread; struct http_conn *httpc = &conn->proto.httpc; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct HTTP *stream = data->req.protop; (void)sockindex; /* we always do HTTP2 on sockindex 0 */ @@ -1297,7 +1392,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, stream->upload_len = 0; /* - * At this point 'stream' is just in the SessionHandle the connection + * At this point 'stream' is just in the Curl_easy the connection * identifies as its owner at this time. */ @@ -1382,6 +1477,8 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, socket is not read. But it seems that usually streams are notified with its drain property, and socket is read again quickly. */ + DEBUGF(infof(data, "stream %x is paused, pause id: %x\n", + stream->stream_id, httpc->pause_stream_id)); *err = CURLE_AGAIN; return -1; } @@ -1497,7 +1594,72 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex, #define HEADER_OVERFLOW(x) \ (x.namelen > (uint16_t)-1 || x.valuelen > (uint16_t)-1 - x.namelen) -/* return number of received (decrypted) bytes */ +/* + * Check header memory for the token "trailers". + * Parse the tokens as separated by comma and surrounded by whitespace. + * Returns TRUE if found or FALSE if not. + */ +static bool contains_trailers(const char *p, size_t len) +{ + const char *end = p + len; + for(;;) { + for(; p != end && (*p == ' ' || *p == '\t'); ++p) + ; + if(p == end || (size_t)(end - p) < sizeof("trailers") - 1) + return FALSE; + if(strncasecompare("trailers", p, sizeof("trailers") - 1)) { + p += sizeof("trailers") - 1; + for(; p != end && (*p == ' ' || *p == '\t'); ++p) + ; + if(p == end || *p == ',') + return TRUE; + } + /* skip to next token */ + for(; p != end && *p != ','; ++p) + ; + if(p == end) + return FALSE; + ++p; + } +} + +typedef enum { + /* Send header to server */ + HEADERINST_FORWARD, + /* Don't send header to server */ + HEADERINST_IGNORE, + /* Discard header, and replace it with "te: trailers" */ + HEADERINST_TE_TRAILERS +} header_instruction; + +/* Decides how to treat given header field. */ +static header_instruction inspect_header(const char *name, size_t namelen, + const char *value, size_t valuelen) { + switch(namelen) { + case 2: + if(!strncasecompare("te", name, namelen)) + return HEADERINST_FORWARD; + + return contains_trailers(value, valuelen) ? + HEADERINST_TE_TRAILERS : HEADERINST_IGNORE; + case 7: + return strncasecompare("upgrade", name, namelen) ? + HEADERINST_IGNORE : HEADERINST_FORWARD; + case 10: + return (strncasecompare("connection", name, namelen) || + strncasecompare("keep-alive", name, namelen)) ? + HEADERINST_IGNORE : HEADERINST_FORWARD; + case 16: + return strncasecompare("proxy-connection", name, namelen) ? + HEADERINST_IGNORE : HEADERINST_FORWARD; + case 17: + return strncasecompare("transfer-encoding", name, namelen) ? + HEADERINST_IGNORE : HEADERINST_FORWARD; + default: + return HEADERINST_FORWARD; + } +} + static ssize_t http2_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *err) { @@ -1513,7 +1675,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, size_t nheader; size_t i; size_t authority_idx; - char *hdbuf = (char*)mem; + char *hdbuf = (char *)mem; char *end, *line_end; nghttp2_data_provider data_prd; int32_t stream_id; @@ -1525,6 +1687,14 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, DEBUGF(infof(conn->data, "http2_send len=%zu\n", len)); if(stream->stream_id != -1) { + if(stream->close_handled) { + infof(conn->data, "stream %d closed\n", stream->stream_id); + *err = CURLE_HTTP2_STREAM; + return -1; + } + else if(stream->closed) { + return http2_handle_stream_close(conn, conn->data, stream, err); + } /* If stream_id != -1, we have dispatched request HEADERS, and now are going to send or sending request body in DATA frame */ stream->upload_mem = mem; @@ -1643,7 +1813,6 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, i = 3; while(i < nheader) { size_t hlen; - int skip = 0; hdbuf = line_end + 2; @@ -1661,12 +1830,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, goto fail; hlen = end - hdbuf; - if(hlen == 10 && Curl_raw_nequal("connection", hdbuf, 10)) { - /* skip Connection: headers! */ - skip = 1; - --nheader; - } - else if(hlen == 4 && Curl_raw_nequal("host", hdbuf, 4)) { + if(hlen == 4 && strncasecompare("host", hdbuf, 4)) { authority_idx = i; nva[i].name = (unsigned char *)":authority"; nva[i].namelen = strlen((char *)nva[i].name); @@ -1679,38 +1843,28 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, while(*hdbuf == ' ' || *hdbuf == '\t') ++hdbuf; end = line_end; - if(!skip) { + + switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf, + end - hdbuf)) { + case HEADERINST_IGNORE: + /* skip header fields prohibited by HTTP/2 specification. */ + --nheader; + continue; + case HEADERINST_TE_TRAILERS: + nva[i].value = (uint8_t*)"trailers"; + nva[i].valuelen = sizeof("trailers") - 1; + break; + default: nva[i].value = (unsigned char *)hdbuf; nva[i].valuelen = (size_t)(end - hdbuf); - nva[i].flags = NGHTTP2_NV_FLAG_NONE; - if(HEADER_OVERFLOW(nva[i])) { - failf(conn->data, "Failed sending HTTP request: Header overflow"); - goto fail; - } - /* Inspect Content-Length header field and retrieve the request - entity length so that we can set END_STREAM to the last DATA - frame. */ - if(nva[i].namelen == 14 && - Curl_raw_nequal("content-length", (char*)nva[i].name, 14)) { - size_t j; - stream->upload_left = 0; - if(!nva[i].valuelen) - goto fail; - for(j = 0; j < nva[i].valuelen; ++j) { - if(nva[i].value[j] < '0' || nva[i].value[j] > '9') - goto fail; - if(stream->upload_left >= CURL_OFF_T_MAX / 10) - goto fail; - stream->upload_left *= 10; - stream->upload_left += nva[i].value[j] - '0'; - } - DEBUGF(infof(conn->data, - "request content-length=%" - CURL_FORMAT_CURL_OFF_T - "\n", stream->upload_left)); - } - ++i; } + + nva[i].flags = NGHTTP2_NV_FLAG_NONE; + if(HEADER_OVERFLOW(nva[i])) { + failf(conn->data, "Failed sending HTTP request: Header overflow"); + goto fail; + } + ++i; } /* :authority must come before non-pseudo header fields */ @@ -1724,24 +1878,22 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, /* Warn stream may be rejected if cumulative length of headers is too large. It appears nghttp2 will not send a header frame larger than 64KB. */ +#define MAX_ACC 60000 /* <64KB to account for some overhead */ { size_t acc = 0; - const size_t max_acc = 60000; /* <64KB to account for some overhead */ for(i = 0; i < nheader; ++i) { - if(nva[i].namelen > max_acc - acc) - break; - acc += nva[i].namelen; + acc += nva[i].namelen + nva[i].valuelen; - if(nva[i].valuelen > max_acc - acc) - break; - acc += nva[i].valuelen; + DEBUGF(infof(conn->data, "h2 header: %.*s:%.*s\n", + nva[i].namelen, nva[i].name, + nva[i].valuelen, nva[i].value)); } - if(i != nheader) { + if(acc > MAX_ACC) { infof(conn->data, "http2_send: Warning: The cumulative length of all " - "headers exceeds %zu bytes and that could cause the " - "stream to be rejected.\n", max_acc); + "headers exceeds %zu bytes and that could cause the " + "stream to be rejected.\n", MAX_ACC); } } @@ -1751,6 +1903,12 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, case HTTPREQ_POST: case HTTPREQ_POST_FORM: case HTTPREQ_PUT: + if(conn->data->state.infilesize != -1) + stream->upload_left = conn->data->state.infilesize; + else + /* data sending without specifying the data amount up front */ + stream->upload_left = -1; /* unknown, but not zero */ + data_prd.read_callback = data_source_read_callback; data_prd.source.ptr = NULL; stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader, @@ -1850,10 +2008,6 @@ CURLcode Curl_http2_setup(struct connectdata *conn) infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n"); Curl_multi_connchanged(conn->data->multi); - /* switch on TCP_NODELAY as we need to send off packets without delay for - maximum throughput */ - Curl_tcpnodelay(conn, conn->sock[FIRSTSOCKET]); - return CURLE_OK; } @@ -1864,7 +2018,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn, struct http_conn *httpc = &conn->proto.httpc; int rv; ssize_t nproc; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct HTTP *stream = conn->data->req.protop; result = Curl_http2_setup(conn); @@ -1893,9 +2047,13 @@ CURLcode Curl_http2_switched(struct connectdata *conn, conn->data); } else { + populate_settings(conn, httpc); + /* stream ID is unknown at this point */ stream->stream_id = -1; - rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, NULL, 0); + rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE, + httpc->local_settings, + httpc->local_settings_num); if(rv != 0) { failf(data, "nghttp2_submit_settings() failed: %s(%d)", nghttp2_strerror(rv), rv); @@ -1903,6 +2061,16 @@ CURLcode Curl_http2_switched(struct connectdata *conn, } } +#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE + rv = nghttp2_session_set_local_window_size(httpc->h2, NGHTTP2_FLAG_NONE, 0, + HTTP2_HUGE_WINDOW_SIZE); + if(rv != 0) { + failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)", + nghttp2_strerror(rv), rv); + return CURLE_HTTP2; + } +#endif + /* we are going to copy mem to httpc->inbuf. This is required since mem is part of buffer pointed by stream->mem, and callbacks called by nghttp2_session_mem_recv() will write stream specific @@ -1918,7 +2086,8 @@ CURLcode Curl_http2_switched(struct connectdata *conn, " after upgrade: len=%zu\n", nread); - memcpy(httpc->inbuf, mem, nread); + if(nread) + memcpy(httpc->inbuf, mem, nread); httpc->inbuflen = nread; nproc = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)httpc->inbuf, @@ -1958,6 +2127,82 @@ CURLcode Curl_http2_switched(struct connectdata *conn, return CURLE_OK; } +void Curl_http2_add_child(struct Curl_easy *parent, struct Curl_easy *child, + bool exclusive) +{ + struct Curl_http2_dep **tail; + struct Curl_http2_dep *dep = calloc(1, sizeof(struct Curl_http2_dep)); + dep->data = child; + + if(parent->set.stream_dependents && exclusive) { + struct Curl_http2_dep *node = parent->set.stream_dependents; + while(node) { + node->data->set.stream_depends_on = child; + node = node->next; + } + + tail = &child->set.stream_dependents; + while(*tail) + tail = &(*tail)->next; + + DEBUGASSERT(!*tail); + *tail = parent->set.stream_dependents; + parent->set.stream_dependents = 0; + } + + tail = &parent->set.stream_dependents; + while(*tail) { + (*tail)->data->set.stream_depends_e = FALSE; + tail = &(*tail)->next; + } + + DEBUGASSERT(!*tail); + *tail = dep; + + child->set.stream_depends_on = parent; + child->set.stream_depends_e = exclusive; +} + +void Curl_http2_remove_child(struct Curl_easy *parent, struct Curl_easy *child) +{ + struct Curl_http2_dep *last = 0; + struct Curl_http2_dep *data = parent->set.stream_dependents; + DEBUGASSERT(child->set.stream_depends_on == parent); + + while(data && data->data != child) { + last = data; + data = data->next; + } + + DEBUGASSERT(data); + + if(data) { + if(last) { + last->next = data->next; + } + else { + parent->set.stream_dependents = data->next; + } + free(data); + } + + child->set.stream_depends_on = 0; + child->set.stream_depends_e = FALSE; +} + +void Curl_http2_cleanup_dependencies(struct Curl_easy *data) +{ + while(data->set.stream_dependents) { + struct Curl_easy *tmp = data->set.stream_dependents->data; + Curl_http2_remove_child(data, tmp); + if(data->set.stream_depends_on) + Curl_http2_add_child(data->set.stream_depends_on, tmp, FALSE); + } + + if(data->set.stream_depends_on) + Curl_http2_remove_child(data->set.stream_depends_on, data); +} + #else /* !USE_NGHTTP2 */ /* Satisfy external references even if http2 is not compiled in. */ diff --git a/contrib/curl/lib/http2.h b/contrib/curl/lib/http2.h index 1aec3040..f405b3ae 100644 --- a/contrib/curl/lib/http2.h +++ b/contrib/curl/lib/http2.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -50,7 +50,14 @@ CURLcode Curl_http2_switched(struct connectdata *conn, const char *data, size_t nread); /* called from Curl_http_setup_conn */ void Curl_http2_setup_conn(struct connectdata *conn); -void Curl_http2_setup_req(struct SessionHandle *data); +void Curl_http2_setup_req(struct Curl_easy *data); +void Curl_http2_done(struct connectdata *conn, bool premature); +CURLcode Curl_http2_done_sending(struct connectdata *conn); +void Curl_http2_add_child(struct Curl_easy *parent, struct Curl_easy *child, + bool exclusive); +void Curl_http2_remove_child(struct Curl_easy *parent, + struct Curl_easy *child); +void Curl_http2_cleanup_dependencies(struct Curl_easy *data); #else /* USE_NGHTTP2 */ #define Curl_http2_init(x) CURLE_UNSUPPORTED_PROTOCOL #define Curl_http2_send_request(x) CURLE_UNSUPPORTED_PROTOCOL @@ -61,6 +68,11 @@ void Curl_http2_setup_req(struct SessionHandle *data); #define Curl_http2_setup_req(x) #define Curl_http2_init_state(x) #define Curl_http2_init_userset(x) +#define Curl_http2_done(x,y) +#define Curl_http2_done_sending(x) +#define Curl_http2_add_child(x, y, z) +#define Curl_http2_remove_child(x, y) +#define Curl_http2_cleanup_dependencies(x) #endif #endif /* HEADER_CURL_HTTP2_H */ diff --git a/contrib/curl/lib/http_chunks.c b/contrib/curl/lib/http_chunks.c index 433f76e1..1bdf6974 100644 --- a/contrib/curl/lib/http_chunks.c +++ b/contrib/curl/lib/http_chunks.c @@ -108,7 +108,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, ssize_t *wrotep) { CURLcode result=CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct Curl_chunker *ch = &conn->chunk; struct SingleRequest *k = &data->req; size_t piece; @@ -190,8 +190,8 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, /* Write the data portion available */ #ifdef HAVE_LIBZ - switch (conn->data->set.http_ce_skip? - IDENTITY : data->req.auto_decoding) { + switch(conn->data->set.http_ce_skip? + IDENTITY : data->req.auto_decoding) { case IDENTITY: #endif if(!k->ignorebody) { @@ -219,10 +219,10 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, break; default: - failf (conn->data, - "Unrecognized content encoding type. " - "libcurl understands `identity', `deflate' and `gzip' " - "content encodings."); + failf(conn->data, + "Unrecognized content encoding type. " + "libcurl understands `identity', `deflate' and `gzip' " + "content encodings."); return CHUNKE_BAD_ENCODING; } #endif @@ -360,7 +360,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn, const char *Curl_chunked_strerror(CHUNKcode code) { - switch (code) { + switch(code) { default: return "OK"; case CHUNKE_TOO_LONG_HEX: diff --git a/contrib/curl/lib/http_digest.c b/contrib/curl/lib/http_digest.c index a1768b86..e2d865b0 100644 --- a/contrib/curl/lib/http_digest.c +++ b/contrib/curl/lib/http_digest.c @@ -25,7 +25,7 @@ #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) #include "urldata.h" -#include "rawstr.h" +#include "strcase.h" #include "vauth/vauth.h" #include "http_digest.h" /* The last 3 #include files should be in this order */ @@ -45,7 +45,7 @@ CURLcode Curl_input_digest(struct connectdata *conn, const char *header) /* rest of the *-authenticate: header */ { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Point to the correct struct with this */ struct digestdata *digest; @@ -73,9 +73,9 @@ CURLcode Curl_output_digest(struct connectdata *conn, const unsigned char *uripath) { CURLcode result; - struct SessionHandle *data = conn->data; - unsigned char *path; - char *tmp; + struct Curl_easy *data = conn->data; + unsigned char *path = NULL; + char *tmp = NULL; char *response; size_t len; bool have_chlg; @@ -95,8 +95,8 @@ CURLcode Curl_output_digest(struct connectdata *conn, if(proxy) { digest = &data->state.proxydigest; allocuserpwd = &conn->allocptr.proxyuserpwd; - userp = conn->proxyuser; - passwdp = conn->proxypasswd; + userp = conn->http_proxy.user; + passwdp = conn->http_proxy.passwd; authp = &data->state.authproxy; } else { @@ -140,12 +140,14 @@ CURLcode Curl_output_digest(struct connectdata *conn, http://www.fngtps.com/2006/09/http-authentication */ - if(authp->iestyle && ((tmp = strchr((char *)uripath, '?')) != NULL)) { - size_t urilen = tmp - (char *)uripath; - - path = (unsigned char *) aprintf("%.*s", urilen, uripath); + if(authp->iestyle) { + tmp = strchr((char *)uripath, '?'); + if(tmp) { + size_t urilen = tmp - (char *)uripath; + path = (unsigned char *) aprintf("%.*s", urilen, uripath); + } } - else + if(!tmp) path = (unsigned char *) strdup((char *) uripath); if(!path) @@ -169,7 +171,7 @@ CURLcode Curl_output_digest(struct connectdata *conn, return CURLE_OK; } -void Curl_digest_cleanup(struct SessionHandle *data) +void Curl_digest_cleanup(struct Curl_easy *data) { Curl_auth_digest_cleanup(&data->state.digest); Curl_auth_digest_cleanup(&data->state.proxydigest); diff --git a/contrib/curl/lib/http_digest.h b/contrib/curl/lib/http_digest.h index 49aad897..fd225c7c 100644 --- a/contrib/curl/lib/http_digest.h +++ b/contrib/curl/lib/http_digest.h @@ -34,7 +34,7 @@ CURLcode Curl_output_digest(struct connectdata *conn, const unsigned char *uripath); #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) -void Curl_digest_cleanup(struct SessionHandle *data); +void Curl_digest_cleanup(struct Curl_easy *data); #else #define Curl_digest_cleanup(x) Curl_nop_stmt #endif diff --git a/contrib/curl/lib/http_negotiate.c b/contrib/curl/lib/http_negotiate.c index 999bc0c5..51375e81 100644 --- a/contrib/curl/lib/http_negotiate.c +++ b/contrib/curl/lib/http_negotiate.c @@ -26,7 +26,6 @@ #include "urldata.h" #include "sendf.h" -#include "rawstr.h" #include "http_negotiate.h" #include "vauth/vauth.h" @@ -38,7 +37,8 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, const char *header) { - struct SessionHandle *data = conn->data; + CURLcode result; + struct Curl_easy *data = conn->data; size_t len; /* Point to the username, password, service and host */ @@ -51,11 +51,11 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, struct negotiatedata *neg_ctx; if(proxy) { - userp = conn->proxyuser; - passwdp = conn->proxypasswd; + userp = conn->http_proxy.user; + passwdp = conn->http_proxy.passwd; service = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP"; - host = conn->proxy.name; + host = conn->http_proxy.host.name; neg_ctx = &data->state.proxyneg; } else { @@ -90,8 +90,13 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, } /* Initilise the security context and decode our challenge */ - return Curl_auth_decode_spnego_message(data, userp, passwdp, service, host, - header, neg_ctx); + result = Curl_auth_decode_spnego_message(data, userp, passwdp, service, + host, header, neg_ctx); + + if(result) + Curl_auth_spnego_cleanup(neg_ctx); + + return result; } CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) @@ -124,7 +129,7 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK; } -void Curl_cleanup_negotiate(struct SessionHandle *data) +void Curl_cleanup_negotiate(struct Curl_easy *data) { Curl_auth_spnego_cleanup(&data->state.negotiate); Curl_auth_spnego_cleanup(&data->state.proxyneg); diff --git a/contrib/curl/lib/http_negotiate.h b/contrib/curl/lib/http_negotiate.h index 21b7f883..c64e5482 100644 --- a/contrib/curl/lib/http_negotiate.h +++ b/contrib/curl/lib/http_negotiate.h @@ -31,7 +31,7 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy, /* this is for creating Negotiate header output */ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy); -void Curl_cleanup_negotiate(struct SessionHandle *data); +void Curl_cleanup_negotiate(struct Curl_easy *data); #endif /* USE_SPNEGO */ diff --git a/contrib/curl/lib/http_ntlm.c b/contrib/curl/lib/http_ntlm.c index 935df25d..8a78bd29 100644 --- a/contrib/curl/lib/http_ntlm.c +++ b/contrib/curl/lib/http_ntlm.c @@ -27,7 +27,7 @@ /* * NTLM details: * - * http://davenport.sourceforge.net/ntlm.html + * https://davenport.sourceforge.io/ntlm.html * https://www.innovation.ch/java/ntlm.html */ @@ -35,7 +35,7 @@ #include "urldata.h" #include "sendf.h" -#include "rawstr.h" +#include "strcase.h" #include "http_ntlm.h" #include "curl_ntlm_wb.h" #include "vauth/vauth.h" @@ -136,8 +136,8 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy) if(proxy) { allocuserpwd = &conn->allocptr.proxyuserpwd; - userp = conn->proxyuser; - passwdp = conn->proxypasswd; + userp = conn->http_proxy.user; + passwdp = conn->http_proxy.passwd; ntlm = &conn->proxyntlm; authp = &conn->data->state.authproxy; } diff --git a/contrib/curl/lib/http_proxy.c b/contrib/curl/lib/http_proxy.c index 814c572f..7fde11db 100644 --- a/contrib/curl/lib/http_proxy.c +++ b/contrib/curl/lib/http_proxy.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -31,19 +31,54 @@ #include "http.h" #include "url.h" #include "select.h" -#include "rawstr.h" #include "progress.h" #include "non-ascii.h" #include "connect.h" #include "curlx.h" +#include "vtls/vtls.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" #include "memdebug.h" -CURLcode Curl_proxy_connect(struct connectdata *conn) +/* + * Perform SSL initialization for HTTPS proxy. Sets + * proxy_ssl_connected connection bit when complete. Can be + * called multiple times. + */ +static CURLcode https_proxy_connect(struct connectdata *conn, int sockindex) { +#ifdef USE_SSL + CURLcode result = CURLE_OK; + DEBUGASSERT(conn->http_proxy.proxytype == CURLPROXY_HTTPS); + if(!conn->bits.proxy_ssl_connected[sockindex]) { + /* perform SSL initialization for this socket */ + result = + Curl_ssl_connect_nonblocking(conn, sockindex, + &conn->bits.proxy_ssl_connected[sockindex]); + if(result) + conn->bits.close = TRUE; /* a failed connection is marked for closure to + prevent (bad) re-use or similar */ + } + return result; +#else + (void) conn; + (void) sockindex; + return CURLE_NOT_BUILT_IN; +#endif +} + +CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex) +{ + if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) { + const CURLcode result = https_proxy_connect(conn, sockindex); + if(result) + return result; + if(!conn->bits.proxy_ssl_connected[sockindex]) + return result; /* wait for HTTPS proxy SSL initialization to complete */ + } + if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { #ifndef CURL_DISABLE_PROXY /* for [protocol] tunneled through HTTP proxy */ @@ -63,21 +98,31 @@ CURLcode Curl_proxy_connect(struct connectdata *conn) * original pointer * * This function might be called several times in the multi interface case - * if the proxy's CONNTECT response is not instant. + * if the proxy's CONNECT response is not instant. */ prot_save = conn->data->req.protop; memset(&http_proxy, 0, sizeof(http_proxy)); conn->data->req.protop = &http_proxy; connkeep(conn, "HTTP proxy CONNECT"); + + /* for the secondary socket (FTP), use the "connect to host" + * but ignore the "connect to port" (use the secondary port) + */ + if(conn->bits.conn_to_host) hostname = conn->conn_to_host.name; + else if(sockindex == SECONDARYSOCKET) + hostname = conn->secondaryhostname; else hostname = conn->host.name; - if(conn->bits.conn_to_port) + + if(sockindex == SECONDARYSOCKET) + remote_port = conn->secondary_port; + else if(conn->bits.conn_to_port) remote_port = conn->conn_to_port; else remote_port = conn->remote_port; - result = Curl_proxyCONNECT(conn, FIRSTSOCKET, hostname, + result = Curl_proxyCONNECT(conn, sockindex, hostname, remote_port, FALSE); conn->data->req.protop = prot_save; if(CURLE_OK != result) @@ -107,14 +152,14 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, bool blocking) { int subversion=0; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; struct SingleRequest *k = &data->req; CURLcode result; curl_socket_t tunnelsocket = conn->sock[sockindex]; curl_off_t cl=0; bool closeConnection = FALSE; bool chunked_encoding = FALSE; - long check; + time_t check; #define SELECT_OK 0 #define SELECT_ERROR 1 @@ -159,9 +204,10 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, free(host_port); if(!result) { - char *host=(char *)""; + char *host = NULL; + const char *proxyconn=""; const char *useragent=""; - const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ? + const char *http = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1"; bool ipv6_ip = conn->bits.ipv6_ip; char *hostheader; @@ -185,6 +231,9 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } } + if(!Curl_checkProxyheaders(conn, "Proxy-Connection:")) + proxyconn = "Proxy-Connection: Keep-Alive\r\n"; + if(!Curl_checkProxyheaders(conn, "User-Agent:") && data->set.str[STRING_USERAGENT]) useragent = conn->allocptr.uagent; @@ -194,15 +243,17 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, "CONNECT %s HTTP/%s\r\n" "%s" /* Host: */ "%s" /* Proxy-Authorization */ - "%s", /* User-Agent */ + "%s" /* User-Agent */ + "%s", /* Proxy-Connection */ hostheader, http, - host, + host?host:"", conn->allocptr.proxyuserpwd? conn->allocptr.proxyuserpwd:"", - useragent); + useragent, + proxyconn); - if(host && *host) + if(host) free(host); free(hostheader); @@ -239,7 +290,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, } if(!blocking) { - if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0)) + if(!Curl_conn_data_pending(conn, sockindex)) /* return so we'll be called again polling-style */ return CURLE_OK; else { @@ -258,13 +309,22 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, char *ptr; char *line_start; - ptr=data->state.buffer; + ptr = data->state.buffer; line_start = ptr; - nread=0; - perline=0; + nread = 0; + perline = 0; - while((nread= &data->state.buffer[BUFSIZE]) { + failf(data, "CONNECT response too large!"); + return CURLE_RECV_ERROR; + } check = Curl_timeleft(data, NULL, TRUE); if(check <= 0) { @@ -273,254 +333,233 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, break; } - /* loop every second at least, less if the timeout is near */ - switch (Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, - check<1000L?check:1000)) { - case -1: /* select() error, stop reading */ - error = SELECT_ERROR; - failf(data, "Proxy CONNECT aborted due to select/poll error"); + /* Read one byte at a time to avoid a race condition. Wait at most one + second before looping to ensure continuous pgrsUpdates. */ + result = Curl_read(conn, tunnelsocket, ptr, 1, &gotbytes); + if(result == CURLE_AGAIN) { + if(SOCKET_READABLE(tunnelsocket, check<1000L?check:1000) == -1) { + error = SELECT_ERROR; + failf(data, "Proxy CONNECT aborted due to select/poll error"); + break; + } + continue; + } + else if(result) { + keepon = FALSE; break; - case 0: /* timeout */ + } + else if(gotbytes <= 0) { + if(data->set.proxyauth && data->state.authproxy.avail) { + /* proxy auth was requested and there was proxy auth available, + then deem this as "mere" proxy disconnect */ + conn->bits.proxy_connect_closed = TRUE; + infof(data, "Proxy CONNECT connection closed\n"); + } + else { + error = SELECT_ERROR; + failf(data, "Proxy CONNECT aborted"); + } + keepon = FALSE; break; - default: - DEBUGASSERT(ptr+BUFSIZE-nread <= data->state.buffer+BUFSIZE+1); - result = Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, - &gotbytes); - if(result==CURLE_AGAIN) - continue; /* go loop yourself */ - else if(result) - keepon = FALSE; - else if(gotbytes <= 0) { - keepon = FALSE; - if(data->set.proxyauth && data->state.authproxy.avail) { - /* proxy auth was requested and there was proxy auth available, - then deem this as "mere" proxy disconnect */ - conn->bits.proxy_connect_closed = TRUE; - infof(data, "Proxy CONNECT connection closed\n"); - } - else { - error = SELECT_ERROR; - failf(data, "Proxy CONNECT aborted"); + } + + /* We got a byte of data */ + nread++; + + if(keepon > TRUE) { + /* This means we are currently ignoring a response-body */ + + nread = 0; /* make next read start over in the read buffer */ + ptr = data->state.buffer; + if(cl) { + /* A Content-Length based body: simply count down the counter + and make sure to break out of the loop when we're done! */ + cl--; + if(cl <= 0) { + keepon = FALSE; + break; } } else { - /* - * We got a whole chunk of data, which can be anything from one - * byte to a set of lines and possibly just a piece of the last - * line. - */ - int i; + /* chunked-encoded body, so we need to do the chunked dance + properly to know when the end of the body is reached */ + CHUNKcode r; + ssize_t tookcareof = 0; - nread += gotbytes; + /* now parse the chunked piece of data so that we can + properly tell when the stream ends */ + r = Curl_httpchunk_read(conn, ptr, 1, &tookcareof); + if(r == CHUNKE_STOP) { + /* we're done reading chunks! */ + infof(data, "chunk reading DONE\n"); + keepon = FALSE; + /* we did the full CONNECT treatment, go COMPLETE */ + conn->tunnel_state[sockindex] = TUNNEL_COMPLETE; + } + } + continue; + } - if(keepon > TRUE) { - /* This means we are currently ignoring a response-body */ + perline++; /* amount of bytes in this line so far */ - nread = 0; /* make next read start over in the read buffer */ - ptr=data->state.buffer; - if(cl) { - /* A Content-Length based body: simply count down the counter - and make sure to break out of the loop when we're done! */ - cl -= gotbytes; - if(cl<=0) { - keepon = FALSE; - break; - } + /* if this is not the end of a header line then continue */ + if(*ptr != 0x0a) { + ptr++; + continue; + } + + /* convert from the network encoding */ + result = Curl_convert_from_network(data, line_start, perline); + /* Curl_convert_from_network calls failf if unsuccessful */ + if(result) + return result; + + /* output debug if that is requested */ + if(data->set.verbose) + Curl_debug(data, CURLINFO_HEADER_IN, + line_start, (size_t)perline, conn); + + /* send the header to the callback */ + writetype = CLIENTWRITE_HEADER; + if(data->set.include_header) + writetype |= CLIENTWRITE_BODY; + + result = Curl_client_write(conn, writetype, line_start, perline); + + data->info.header_size += (long)perline; + data->req.headerbytecount += (long)perline; + + if(result) + return result; + + /* Newlines are CRLF, so the CR is ignored as the line isn't + really terminated until the LF comes. Treat a following CR + as end-of-headers as well.*/ + + if(('\r' == line_start[0]) || + ('\n' == line_start[0])) { + /* end of response-headers from the proxy */ + nread = 0; /* make next read start over in the read + buffer */ + ptr = data->state.buffer; + if((407 == k->httpcode) && !data->state.authproblem) { + /* If we get a 407 response code with content length + when we have no auth problem, we must ignore the + whole response-body */ + keepon = 2; + + if(cl) { + infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T + " bytes of response-body\n", cl); + } + else if(chunked_encoding) { + CHUNKcode r; + + infof(data, "Ignore chunked response-body\n"); + + /* We set ignorebody true here since the chunked + decoder function will acknowledge that. Pay + attention so that this is cleared again when this + function returns! */ + k->ignorebody = TRUE; + + if(line_start[1] == '\n') { + /* this can only be a LF if the letter at index 0 + was a CR */ + line_start++; } - else { - /* chunked-encoded body, so we need to do the chunked dance - properly to know when the end of the body is reached */ - CHUNKcode r; - ssize_t tookcareof=0; - /* now parse the chunked piece of data so that we can - properly tell when the stream ends */ - r = Curl_httpchunk_read(conn, ptr, gotbytes, &tookcareof); - if(r == CHUNKE_STOP) { - /* we're done reading chunks! */ - infof(data, "chunk reading DONE\n"); - keepon = FALSE; - /* we did the full CONNECT treatment, go COMPLETE */ - conn->tunnel_state[sockindex] = TUNNEL_COMPLETE; - } - else - infof(data, "Read %zd bytes of chunk, continue\n", - tookcareof); + /* now parse the chunked piece of data so that we can + properly tell when the stream ends */ + r = Curl_httpchunk_read(conn, line_start + 1, 1, &gotbytes); + if(r == CHUNKE_STOP) { + /* we're done reading chunks! */ + infof(data, "chunk reading DONE\n"); + keepon = FALSE; + /* we did the full CONNECT treatment, go to + COMPLETE */ + conn->tunnel_state[sockindex] = TUNNEL_COMPLETE; } } - else - for(i = 0; i < gotbytes; ptr++, i++) { - perline++; /* amount of bytes in this line so far */ - if(*ptr == 0x0a) { - char letter; - int writetype; - - /* convert from the network encoding */ - result = Curl_convert_from_network(data, line_start, - perline); - /* Curl_convert_from_network calls failf if unsuccessful */ - if(result) - return result; - - /* output debug if that is requested */ - if(data->set.verbose) - Curl_debug(data, CURLINFO_HEADER_IN, - line_start, (size_t)perline, conn); - - /* send the header to the callback */ - writetype = CLIENTWRITE_HEADER; - if(data->set.include_header) - writetype |= CLIENTWRITE_BODY; - - result = Curl_client_write(conn, writetype, line_start, - perline); - - data->info.header_size += (long)perline; - data->req.headerbytecount += (long)perline; - - if(result) - return result; - - /* Newlines are CRLF, so the CR is ignored as the line isn't - really terminated until the LF comes. Treat a following CR - as end-of-headers as well.*/ - - if(('\r' == line_start[0]) || - ('\n' == line_start[0])) { - /* end of response-headers from the proxy */ - nread = 0; /* make next read start over in the read - buffer */ - ptr=data->state.buffer; - if((407 == k->httpcode) && !data->state.authproblem) { - /* If we get a 407 response code with content length - when we have no auth problem, we must ignore the - whole response-body */ - keepon = 2; - - if(cl) { - infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T - " bytes of response-body\n", cl); - - /* remove the remaining chunk of what we already - read */ - cl -= (gotbytes - i); - - if(cl<=0) - /* if the whole thing was already read, we are done! - */ - keepon=FALSE; - } - else if(chunked_encoding) { - CHUNKcode r; - /* We set ignorebody true here since the chunked - decoder function will acknowledge that. Pay - attention so that this is cleared again when this - function returns! */ - k->ignorebody = TRUE; - infof(data, "%zd bytes of chunk left\n", gotbytes-i); - - if(line_start[1] == '\n') { - /* this can only be a LF if the letter at index 0 - was a CR */ - line_start++; - i++; - } - - /* now parse the chunked piece of data so that we can - properly tell when the stream ends */ - r = Curl_httpchunk_read(conn, line_start+1, - gotbytes -i, &gotbytes); - if(r == CHUNKE_STOP) { - /* we're done reading chunks! */ - infof(data, "chunk reading DONE\n"); - keepon = FALSE; - /* we did the full CONNECT treatment, go to - COMPLETE */ - conn->tunnel_state[sockindex] = TUNNEL_COMPLETE; - } - else - infof(data, "Read %zd bytes of chunk, continue\n", - gotbytes); - } - else { - /* without content-length or chunked encoding, we - can't keep the connection alive since the close is - the end signal so we bail out at once instead */ - keepon=FALSE; - } - } - else { - keepon = FALSE; - if(200 == data->info.httpproxycode) { - if(gotbytes - (i+1)) - failf(data, "Proxy CONNECT followed by %zd bytes " - "of opaque data. Data ignored (known bug #39)", - gotbytes - (i+1)); - } - } - /* we did the full CONNECT treatment, go to COMPLETE */ - conn->tunnel_state[sockindex] = TUNNEL_COMPLETE; - break; /* breaks out of for-loop, not switch() */ - } - - /* keep a backup of the position we are about to blank */ - letter = line_start[perline]; - line_start[perline]=0; /* zero terminate the buffer */ - if((checkprefix("WWW-Authenticate:", line_start) && - (401 == k->httpcode)) || - (checkprefix("Proxy-authenticate:", line_start) && - (407 == k->httpcode))) { - - bool proxy = (k->httpcode == 407) ? TRUE : FALSE; - char *auth = Curl_copy_header_value(line_start); - if(!auth) - return CURLE_OUT_OF_MEMORY; - - result = Curl_http_input_auth(conn, proxy, auth); - - free(auth); - - if(result) - return result; - } - else if(checkprefix("Content-Length:", line_start)) { - cl = curlx_strtoofft(line_start + - strlen("Content-Length:"), NULL, 10); - } - else if(Curl_compareheader(line_start, - "Connection:", "close")) - closeConnection = TRUE; - else if(Curl_compareheader(line_start, - "Transfer-Encoding:", - "chunked")) { - infof(data, "CONNECT responded chunked\n"); - chunked_encoding = TRUE; - /* init our chunky engine */ - Curl_httpchunk_init(conn); - } - else if(Curl_compareheader(line_start, - "Proxy-Connection:", "close")) - closeConnection = TRUE; - else if(2 == sscanf(line_start, "HTTP/1.%d %d", - &subversion, - &k->httpcode)) { - /* store the HTTP code from the proxy */ - data->info.httpproxycode = k->httpcode; - } - /* put back the letter we blanked out before */ - line_start[perline]= letter; - - perline=0; /* line starts over here */ - line_start = ptr+1; /* this skips the zero byte we wrote */ - } - } + else { + /* without content-length or chunked encoding, we + can't keep the connection alive since the close is + the end signal so we bail out at once instead */ + keepon = FALSE; + } } - break; - } /* switch */ - if(Curl_pgrsUpdate(conn)) - return CURLE_ABORTED_BY_CALLBACK; + else + keepon = FALSE; + /* we did the full CONNECT treatment, go to COMPLETE */ + conn->tunnel_state[sockindex] = TUNNEL_COMPLETE; + continue; + } + + line_start[perline] = 0; /* zero terminate the buffer */ + if((checkprefix("WWW-Authenticate:", line_start) && + (401 == k->httpcode)) || + (checkprefix("Proxy-authenticate:", line_start) && + (407 == k->httpcode))) { + + bool proxy = (k->httpcode == 407) ? TRUE : FALSE; + char *auth = Curl_copy_header_value(line_start); + if(!auth) + return CURLE_OUT_OF_MEMORY; + + result = Curl_http_input_auth(conn, proxy, auth); + + free(auth); + + if(result) + return result; + } + else if(checkprefix("Content-Length:", line_start)) { + if(k->httpcode/100 == 2) { + /* A server MUST NOT send any Transfer-Encoding or + Content-Length header fields in a 2xx (Successful) + response to CONNECT. (RFC 7231 section 4.3.6) */ + failf(data, "Content-Length: in %03d response", + k->httpcode); + return CURLE_RECV_ERROR; + } + + cl = curlx_strtoofft(line_start + + strlen("Content-Length:"), NULL, 10); + } + else if(Curl_compareheader(line_start, "Connection:", "close")) + closeConnection = TRUE; + else if(Curl_compareheader(line_start, + "Transfer-Encoding:", + "chunked")) { + if(k->httpcode/100 == 2) { + /* A server MUST NOT send any Transfer-Encoding or + Content-Length header fields in a 2xx (Successful) + response to CONNECT. (RFC 7231 section 4.3.6) */ + failf(data, "Transfer-Encoding: in %03d response", k->httpcode); + return CURLE_RECV_ERROR; + } + infof(data, "CONNECT responded chunked\n"); + chunked_encoding = TRUE; + /* init our chunky engine */ + Curl_httpchunk_init(conn); + } + else if(Curl_compareheader(line_start, "Proxy-Connection:", "close")) + closeConnection = TRUE; + else if(2 == sscanf(line_start, "HTTP/1.%d %d", + &subversion, + &k->httpcode)) { + /* store the HTTP code from the proxy */ + data->info.httpproxycode = k->httpcode; + } + + perline = 0; /* line starts over here */ + ptr = data->state.buffer; + line_start = ptr; } /* while there's buffer left and loop is requested */ + if(Curl_pgrsUpdate(conn)) + return CURLE_ABORTED_BY_CALLBACK; + if(error) return CURLE_RECV_ERROR; @@ -534,8 +573,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, if(conn->bits.close) /* the connection has been marked for closure, most likely in the Curl_http_auth_act() function and thus we can kill it at once - below - */ + below */ closeConnection = TRUE; } @@ -568,7 +606,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, free(data->req.newurl); data->req.newurl = NULL; /* failure, close this connection to avoid re-use */ - connclose(conn, "proxy CONNECT failure"); + streamclose(conn, "proxy CONNECT failure"); Curl_closesocket(conn, conn->sock[sockindex]); conn->sock[sockindex] = CURL_SOCKET_BAD; } @@ -596,7 +634,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, data->state.authproxy.done = TRUE; - infof (data, "Proxy replied OK to CONNECT request\n"); + infof(data, "Proxy replied OK to CONNECT request\n"); data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */ conn->bits.rewindaftersend = FALSE; /* make sure this isn't set for the document request */ diff --git a/contrib/curl/lib/http_proxy.h b/contrib/curl/lib/http_proxy.h index fd043303..d1f5a7c8 100644 --- a/contrib/curl/lib/http_proxy.h +++ b/contrib/curl/lib/http_proxy.h @@ -32,11 +32,11 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, /* Default proxy timeout in milliseconds */ #define PROXY_TIMEOUT (3600*1000) -CURLcode Curl_proxy_connect(struct connectdata *conn); +CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex); #else #define Curl_proxyCONNECT(x,y,z,w,v) CURLE_NOT_BUILT_IN -#define Curl_proxy_connect(x) CURLE_OK +#define Curl_proxy_connect(x,y) CURLE_OK #endif #endif /* HEADER_CURL_HTTP_PROXY_H */ diff --git a/contrib/curl/lib/if2ip.c b/contrib/curl/lib/if2ip.c index 2f92b2de..d876615e 100644 --- a/contrib/curl/lib/if2ip.c +++ b/contrib/curl/lib/if2ip.c @@ -51,7 +51,7 @@ #endif #include "inet_ntop.h" -#include "strequal.h" +#include "strcase.h" #include "if2ip.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -68,7 +68,7 @@ unsigned int Curl_ipv6_scope(const struct sockaddr *sa) #else if(sa->sa_family == AF_INET6) { const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *)(void *) sa; - const unsigned char * b = sa6->sin6_addr.s6_addr; + const unsigned char *b = sa6->sin6_addr.s6_addr; unsigned short w = (unsigned short) ((b[0] << 8) | b[1]); switch(w & 0xFFC0) { @@ -102,7 +102,7 @@ bool Curl_if_is_interface_name(const char *interf) if(getifaddrs(&head) >= 0) { for(iface=head; iface != NULL; iface=iface->ifa_next) { - if(curl_strequal(iface->ifa_name, interf)) { + if(strcasecompare(iface->ifa_name, interf)) { result = TRUE; break; } @@ -132,7 +132,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, for(iface = head; iface != NULL; iface=iface->ifa_next) { if(iface->ifa_addr != NULL) { if(iface->ifa_addr->sa_family == af) { - if(curl_strequal(iface->ifa_name, interf)) { + if(strcasecompare(iface->ifa_name, interf)) { void *addr; char *ip; char scope[12] = ""; @@ -180,7 +180,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope, } } else if((res == IF2IP_NOT_FOUND) && - curl_strequal(iface->ifa_name, interf)) { + strcasecompare(iface->ifa_name, interf)) { res = IF2IP_AF_NOT_SUPPORTED; } } diff --git a/contrib/curl/lib/imap.c b/contrib/curl/lib/imap.c index 16ba402c..44d350be 100644 --- a/contrib/curl/lib/imap.c +++ b/contrib/curl/lib/imap.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -68,16 +68,15 @@ #include "http.h" /* for HTTP proxy tunnel stuff */ #include "socks.h" #include "imap.h" - #include "strtoofft.h" -#include "strequal.h" +#include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" -#include "rawstr.h" +#include "strcase.h" #include "curl_sasl.h" #include "warnless.h" @@ -108,7 +107,7 @@ static CURLcode imap_perform_authenticate(struct connectdata *conn, const char *initresp); static CURLcode imap_continue_authenticate(struct connectdata *conn, const char *resp); -static void imap_get_message(char *buffer, char** outptr); +static void imap_get_message(char *buffer, char **outptr); /* * IMAP protocol handler. @@ -131,7 +130,8 @@ const struct Curl_handler Curl_handler_imap = { ZERO_NULL, /* readwrite */ PORT_IMAP, /* defport */ CURLPROTO_IMAP, /* protocol */ - PROTOPT_CLOSEACTION /* flags */ + PROTOPT_CLOSEACTION| /* flags */ + PROTOPT_URLOPTIONS }; #ifdef USE_SSL @@ -271,7 +271,7 @@ static bool imap_matchresp(const char *line, size_t len, const char *cmd) /* Does the command name match and is it followed by a space character or at the end of line? */ - if(line + cmd_len <= end && Curl_raw_nequal(line, cmd, cmd_len) && + if(line + cmd_len <= end && strncasecompare(line, cmd, cmd_len) && (line[cmd_len] == ' ' || line + cmd_len + 2 == end)) return TRUE; @@ -391,10 +391,10 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len, * * Gets the authentication message from the response buffer. */ -static void imap_get_message(char *buffer, char** outptr) +static void imap_get_message(char *buffer, char **outptr) { size_t len = 0; - char* message = NULL; + char *message = NULL; /* Find the start of the message */ for(message = buffer + 2; *message == ' ' || *message == '\t'; message++) @@ -648,7 +648,7 @@ static CURLcode imap_perform_authentication(struct connectdata *conn) static CURLcode imap_perform_list(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; char *mailbox; @@ -683,7 +683,7 @@ static CURLcode imap_perform_list(struct connectdata *conn) static CURLcode imap_perform_select(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; struct imap_conn *imapc = &conn->proto.imapc; char *mailbox; @@ -840,13 +840,13 @@ static CURLcode imap_state_servergreet_resp(struct connectdata *conn, imapstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(imapcode != 'O') { failf(data, "Got unexpected imap-server response"); - result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */ + result = CURLE_WEIRD_SERVER_REPLY; } else result = imap_perform_capability(conn); @@ -860,7 +860,7 @@ static CURLcode imap_state_capability_resp(struct connectdata *conn, imapstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct imap_conn *imapc = &conn->proto.imapc; const char *line = data->state.buffer; size_t wordlen; @@ -947,13 +947,13 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn, imapstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(imapcode != 'O') { if(data->set.use_ssl != CURLUSESSL_TRY) { - failf(data, "STARTTLS denied. %c", imapcode); + failf(data, "STARTTLS denied"); result = CURLE_USE_SSL_FAILED; } else @@ -971,7 +971,7 @@ static CURLcode imap_state_auth_resp(struct connectdata *conn, imapstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct imap_conn *imapc = &conn->proto.imapc; saslprogress progress; @@ -1005,7 +1005,7 @@ static CURLcode imap_state_login_resp(struct connectdata *conn, imapstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -1051,7 +1051,7 @@ static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct IMAP *imap = conn->data->req.protop; struct imap_conn *imapc = &conn->proto.imapc; const char *line = data->state.buffer; @@ -1098,7 +1098,7 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct imap_conn *imapc = &conn->proto.imapc; struct pingpong *pp = &imapc->pp; const char *ptr = data->state.buffer; @@ -1179,7 +1179,7 @@ static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode, else { /* We don't know how to parse this line */ failf(pp->conn->data, "Failed to parse FETCH response."); - result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */ + result = CURLE_WEIRD_SERVER_REPLY; } /* End of DO phase */ @@ -1198,7 +1198,7 @@ static CURLcode imap_state_fetch_final_resp(struct connectdata *conn, (void)instate; /* No use for this yet */ if(imapcode != 'O') - result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: Fix error code */ + result = CURLE_WEIRD_SERVER_REPLY; else /* End of DONE phase */ state(conn, IMAP_STOP); @@ -1211,7 +1211,7 @@ static CURLcode imap_state_append_resp(struct connectdata *conn, int imapcode, imapstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* No use for this yet */ @@ -1275,7 +1275,7 @@ static CURLcode imap_statemach_act(struct connectdata *conn) /* Was there an error parsing the response line? */ if(imapcode == -1) - return CURLE_FTP_WEIRD_SERVER_REPLY; + return CURLE_WEIRD_SERVER_REPLY; if(!imapcode) break; @@ -1371,12 +1371,12 @@ static CURLcode imap_block_statemach(struct connectdata *conn) return result; } -/* Allocate and initialize the struct IMAP for the current SessionHandle if +/* Allocate and initialize the struct IMAP for the current Curl_easy if required */ static CURLcode imap_init(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct IMAP *imap; imap = data->req.protop = calloc(sizeof(struct IMAP), 1); @@ -1456,7 +1456,7 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status, bool premature) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; (void)premature; @@ -1518,7 +1518,7 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected, { /* This is IMAP and no proxy */ CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; struct imap_conn *imapc = &conn->proto.imapc; bool selected = FALSE; @@ -1683,7 +1683,7 @@ static CURLcode imap_regular_transfer(struct connectdata *conn, { CURLcode result = CURLE_OK; bool connected = FALSE; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Make sure size is unknown at this point */ data->req.size = -1; @@ -1706,7 +1706,7 @@ static CURLcode imap_regular_transfer(struct connectdata *conn, static CURLcode imap_setup_connection(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Initialise the IMAP layer */ CURLcode result = imap_init(conn); @@ -1935,7 +1935,7 @@ static CURLcode imap_parse_url_options(struct connectdata *conn) while(*ptr && *ptr != ';') ptr++; - if(strnequal(key, "AUTH=", 5)) + if(strncasecompare(key, "AUTH=", 5)) result = Curl_sasl_parse_url_auth_option(&imapc->sasl, value, ptr - value); else @@ -1971,7 +1971,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn) { /* The imap struct is already initialised in imap_connect() */ CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; const char *begin = data->state.path; const char *ptr = begin; @@ -2031,28 +2031,28 @@ static CURLcode imap_parse_url_path(struct connectdata *conn) PARTIAL) stripping of the trailing slash character if it is present. Note: Unknown parameters trigger a URL_MALFORMAT error. */ - if(Curl_raw_equal(name, "UIDVALIDITY") && !imap->uidvalidity) { + if(strcasecompare(name, "UIDVALIDITY") && !imap->uidvalidity) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->uidvalidity = value; value = NULL; } - else if(Curl_raw_equal(name, "UID") && !imap->uid) { + else if(strcasecompare(name, "UID") && !imap->uid) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->uid = value; value = NULL; } - else if(Curl_raw_equal(name, "SECTION") && !imap->section) { + else if(strcasecompare(name, "SECTION") && !imap->section) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; imap->section = value; value = NULL; } - else if(Curl_raw_equal(name, "PARTIAL") && !imap->partial) { + else if(strcasecompare(name, "PARTIAL") && !imap->partial) { if(valuelen > 0 && value[valuelen - 1] == '/') value[valuelen - 1] = '\0'; @@ -2101,7 +2101,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn) static CURLcode imap_parse_custom_request(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct IMAP *imap = data->req.protop; const char *custom = data->set.str[STRING_CUSTOMREQUEST]; diff --git a/contrib/curl/lib/imap.h b/contrib/curl/lib/imap.h index e6b9b894..5e0e228f 100644 --- a/contrib/curl/lib/imap.h +++ b/contrib/curl/lib/imap.h @@ -49,9 +49,9 @@ typedef enum { IMAP_LAST /* never used */ } imapstate; -/* This IMAP struct is used in the SessionHandle. All IMAP data that is +/* This IMAP struct is used in the Curl_easy. All IMAP data that is connection-oriented must be in imap_conn to properly deal with the fact that - perhaps the SessionHandle is changed between the times the connection is + perhaps the Curl_easy is changed between the times the connection is used. */ struct IMAP { curl_pp_transfer transfer; diff --git a/contrib/curl/lib/inet_ntop.c b/contrib/curl/lib/inet_ntop.c index 416005c0..9afbdbb3 100644 --- a/contrib/curl/lib/inet_ntop.c +++ b/contrib/curl/lib/inet_ntop.c @@ -182,12 +182,12 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size) */ char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size) { - switch (af) { + switch(af) { case AF_INET: - return inet_ntop4((const unsigned char*)src, buf, size); + return inet_ntop4((const unsigned char *)src, buf, size); #ifdef ENABLE_IPV6 case AF_INET6: - return inet_ntop6((const unsigned char*)src, buf, size); + return inet_ntop6((const unsigned char *)src, buf, size); #endif default: SET_ERRNO(EAFNOSUPPORT); diff --git a/contrib/curl/lib/inet_pton.c b/contrib/curl/lib/inet_pton.c index cf8b88a1..475f44ab 100644 --- a/contrib/curl/lib/inet_pton.c +++ b/contrib/curl/lib/inet_pton.c @@ -65,7 +65,7 @@ static int inet_pton6(const char *src, unsigned char *dst); int Curl_inet_pton(int af, const char *src, void *dst) { - switch (af) { + switch(af) { case AF_INET: return (inet_pton4(src, (unsigned char *)dst)); #ifdef ENABLE_IPV6 @@ -103,7 +103,8 @@ inet_pton4(const char *src, unsigned char *dst) while((ch = *src++) != '\0') { const char *pch; - if((pch = strchr(digits, ch)) != NULL) { + pch = strchr(digits, ch); + if(pch) { unsigned int val = *tp * 10 + (unsigned int)(pch - digits); if(saw_digit && *tp == 0) @@ -169,7 +170,8 @@ inet_pton6(const char *src, unsigned char *dst) while((ch = *src++) != '\0') { const char *pch; - if((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_l), ch); + if(!pch) pch = strchr((xdigits = xdigits_u), ch); if(pch != NULL) { val <<= 4; diff --git a/contrib/curl/lib/krb5.c b/contrib/curl/lib/krb5.c index 0b146e06..067b0a57 100644 --- a/contrib/curl/lib/krb5.c +++ b/contrib/curl/lib/krb5.c @@ -121,7 +121,7 @@ krb5_encode(void *app_data, const void *from, int length, int level, void **to) /* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal * libraries modify the input buffer in gss_seal() */ - dec.value = (void*)from; + dec.value = (void *)from; dec.length = length; maj = gss_seal(&min, *context, level == PROT_PRIVATE, @@ -150,7 +150,7 @@ krb5_auth(void *app_data, struct connectdata *conn) const char *host = conn->host.name; ssize_t nread; curl_socklen_t l = sizeof(conn->local_addr); - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result; const char *service = data->set.str[STRING_SERVICE_NAME] ? data->set.str[STRING_SERVICE_NAME] : @@ -182,7 +182,7 @@ krb5_auth(void *app_data, struct connectdata *conn) for(;;) { /* this really shouldn't be repeated here, but can't help it */ if(service == srv_host) { - result = Curl_ftpsendf(conn, "AUTH GSSAPI"); + result = Curl_ftpsend(conn, "AUTH GSSAPI"); if(result) return -2; @@ -243,16 +243,22 @@ krb5_auth(void *app_data, struct connectdata *conn) } if(output_buffer.length != 0) { + char *cmd; + result = Curl_base64_encode(data, (char *)output_buffer.value, output_buffer.length, &p, &base64_sz); if(result) { Curl_infof(data, "base64-encoding: %s\n", curl_easy_strerror(result)); - ret = AUTH_CONTINUE; + ret = AUTH_ERROR; break; } - result = Curl_ftpsendf(conn, "ADAT %s", p); + cmd = aprintf("ADAT %s", p); + if(cmd) + result = Curl_ftpsend(conn, cmd); + else + result = CURLE_OUT_OF_MEMORY; free(p); diff --git a/contrib/curl/lib/ldap.c b/contrib/curl/lib/ldap.c index 1f1f72fb..979ce7de 100644 --- a/contrib/curl/lib/ldap.c +++ b/contrib/curl/lib/ldap.c @@ -69,12 +69,11 @@ #include "escape.h" #include "progress.h" #include "transfer.h" -#include "strequal.h" +#include "strcase.h" #include "strtok.h" #include "curl_ldap.h" #include "curl_multibyte.h" #include "curl_base64.h" -#include "rawstr.h" #include "connect.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -110,9 +109,9 @@ typedef struct { #undef LDAPURLDesc #define LDAPURLDesc CURL_LDAPURLDesc -static int _ldap_url_parse (const struct connectdata *conn, - LDAPURLDesc **ludp); -static void _ldap_free_urldesc (LDAPURLDesc *ludp); +static int _ldap_url_parse(const struct connectdata *conn, + LDAPURLDesc **ludp); +static void _ldap_free_urldesc(LDAPURLDesc *ludp); #undef ldap_free_urldesc #define ldap_free_urldesc _ldap_free_urldesc @@ -120,11 +119,11 @@ static void _ldap_free_urldesc (LDAPURLDesc *ludp); #ifdef DEBUG_LDAP #define LDAP_TRACE(x) do { \ - _ldap_trace ("%u: ", __LINE__); \ + _ldap_trace("%u: ", __LINE__); \ _ldap_trace x; \ } WHILE_FALSE - static void _ldap_trace (const char *fmt, ...); + static void _ldap_trace(const char *fmt, ...); #else #define LDAP_TRACE(x) Curl_nop_stmt #endif @@ -192,7 +191,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) LDAPMessage *ldapmsg = NULL; LDAPMessage *entryIterator; int num = 0; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; int ldap_proto = LDAP_VERSION3; int ldap_ssl = 0; char *val_b64 = NULL; @@ -272,7 +271,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON); #else int ldap_option; - char* ldap_ca = data->set.str[STRING_SSL_CAFILE]; + char *ldap_ca = conn->ssl_config.CAfile; #if defined(CURL_HAS_NOVELL_LDAPSDK) rc = ldapssl_client_init(NULL, NULL); if(rc != LDAP_SUCCESS) { @@ -280,11 +279,11 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) result = CURLE_SSL_CERTPROBLEM; goto quit; } - if(data->set.ssl.verifypeer) { + if(conn->ssl_config.verifypeer) { /* Novell SDK supports DER or BASE64 files. */ int cert_type = LDAPSSL_CERT_FILETYPE_B64; - if((data->set.str[STRING_CERT_TYPE]) && - (Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "DER"))) + if((data->set.ssl.cert_type) && + (strcasecompare(data->set.ssl.cert_type, "DER"))) cert_type = LDAPSSL_CERT_FILETYPE_DER; if(!ldap_ca) { failf(data, "LDAP local: ERROR %s CA cert not set!", @@ -322,10 +321,10 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) goto quit; } #elif defined(LDAP_OPT_X_TLS) - if(data->set.ssl.verifypeer) { + if(conn->ssl_config.verifypeer) { /* OpenLDAP SDK supports BASE64 files. */ - if((data->set.str[STRING_CERT_TYPE]) && - (!Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "PEM"))) { + if((data->set.ssl.cert_type) && + (!strcasecompare(data->set.ssl.cert_type, "PEM"))) { failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!"); result = CURLE_SSL_CERTPROBLEM; goto quit; @@ -656,7 +655,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) quit: if(ldapmsg) { ldap_msgfree(ldapmsg); - LDAP_TRACE (("Received %d entries\n", num)); + LDAP_TRACE(("Received %d entries\n", num)); } if(rc == LDAP_SIZELIMIT_EXCEEDED) infof(data, "There are more than %d entries\n", num); @@ -683,7 +682,7 @@ quit: } #ifdef DEBUG_LDAP -static void _ldap_trace (const char *fmt, ...) +static void _ldap_trace(const char *fmt, ...) { static int do_trace = -1; va_list args; @@ -695,9 +694,9 @@ static void _ldap_trace (const char *fmt, ...) if(!do_trace) return; - va_start (args, fmt); - vfprintf (stderr, fmt, args); - va_end (args); + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); } #endif @@ -706,18 +705,18 @@ static void _ldap_trace (const char *fmt, ...) /* * Return scope-value for a scope-string. */ -static int str2scope (const char *p) +static int str2scope(const char *p) { - if(strequal(p, "one")) - return LDAP_SCOPE_ONELEVEL; - if(strequal(p, "onetree")) - return LDAP_SCOPE_ONELEVEL; - if(strequal(p, "base")) - return LDAP_SCOPE_BASE; - if(strequal(p, "sub")) - return LDAP_SCOPE_SUBTREE; - if(strequal(p, "subtree")) - return LDAP_SCOPE_SUBTREE; + if(strcasecompare(p, "one")) + return LDAP_SCOPE_ONELEVEL; + if(strcasecompare(p, "onetree")) + return LDAP_SCOPE_ONELEVEL; + if(strcasecompare(p, "base")) + return LDAP_SCOPE_BASE; + if(strcasecompare(p, "sub")) + return LDAP_SCOPE_SUBTREE; + if(strcasecompare(p, "subtree")) + return LDAP_SCOPE_SUBTREE; return (-1); } @@ -767,7 +766,7 @@ static bool split_str(char *str, char ***out, size_t *count) * * Defined in RFC4516 section 2. */ -static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) +static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp) { int rc = LDAP_SUCCESS; char *path; @@ -776,9 +775,9 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) size_t i; if(!conn->data || - !conn->data->state.path || - conn->data->state.path[0] != '/' || - !checkprefix("LDAP", conn->data->change.url)) + !conn->data->state.path || + conn->data->state.path[0] != '/' || + !checkprefix("LDAP", conn->data->change.url)) return LDAP_INVALID_SYNTAX; ludp->lud_scope = LDAP_SCOPE_BASE; @@ -798,12 +797,13 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) if(*p) { char *dn = p; char *unescaped; + CURLcode result; - LDAP_TRACE (("DN '%s'\n", dn)); + LDAP_TRACE(("DN '%s'\n", dn)); /* Unescape the DN */ - unescaped = curl_easy_unescape(conn->data, dn, 0, NULL); - if(!unescaped) { + result = Curl_urldecode(conn->data, dn, 0, &unescaped, NULL, FALSE); + if(result) { rc = LDAP_NO_MEMORY; goto quit; @@ -862,12 +862,14 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) for(i = 0; i < count; i++) { char *unescaped; + CURLcode result; - LDAP_TRACE (("attr[%d] '%s'\n", i, attributes[i])); + LDAP_TRACE(("attr[%d] '%s'\n", i, attributes[i])); /* Unescape the attribute */ - unescaped = curl_easy_unescape(conn->data, attributes[i], 0, NULL); - if(!unescaped) { + result = Curl_urldecode(conn->data, attributes[i], 0, &unescaped, NULL, + FALSE); + if(result) { free(attributes); rc = LDAP_NO_MEMORY; @@ -915,7 +917,7 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) goto quit; } - LDAP_TRACE (("scope %d\n", ludp->lud_scope)); + LDAP_TRACE(("scope %d\n", ludp->lud_scope)); } p = q; @@ -930,12 +932,13 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) if(*p) { char *filter = p; char *unescaped; + CURLcode result; - LDAP_TRACE (("filter '%s'\n", filter)); + LDAP_TRACE(("filter '%s'\n", filter)); /* Unescape the filter */ - unescaped = curl_easy_unescape(conn->data, filter, 0, NULL); - if(!unescaped) { + result = Curl_urldecode(conn->data, filter, 0, &unescaped, NULL, FALSE); + if(result) { rc = LDAP_NO_MEMORY; goto quit; @@ -971,8 +974,8 @@ quit: return rc; } -static int _ldap_url_parse (const struct connectdata *conn, - LDAPURLDesc **ludpp) +static int _ldap_url_parse(const struct connectdata *conn, + LDAPURLDesc **ludpp) { LDAPURLDesc *ludp = calloc(1, sizeof(*ludp)); int rc; @@ -981,7 +984,7 @@ static int _ldap_url_parse (const struct connectdata *conn, if(!ludp) return LDAP_NO_MEMORY; - rc = _ldap_url_parse2 (conn, ludp); + rc = _ldap_url_parse2(conn, ludp); if(rc != LDAP_SUCCESS) { _ldap_free_urldesc(ludp); ludp = NULL; @@ -990,7 +993,7 @@ static int _ldap_url_parse (const struct connectdata *conn, return (rc); } -static void _ldap_free_urldesc (LDAPURLDesc *ludp) +static void _ldap_free_urldesc(LDAPURLDesc *ludp) { size_t i; @@ -1006,7 +1009,7 @@ static void _ldap_free_urldesc (LDAPURLDesc *ludp) free(ludp->lud_attrs); } - free (ludp); + free(ludp); } #endif /* !HAVE_LDAP_URL_PARSE */ #endif /* !CURL_DISABLE_LDAP && !USE_OPENLDAP */ diff --git a/contrib/curl/lib/libcurl.def b/contrib/curl/lib/libcurl.def deleted file mode 100644 index e0125572..00000000 --- a/contrib/curl/lib/libcurl.def +++ /dev/null @@ -1,53 +0,0 @@ -; -; Definition file for the DLL version of the LIBCURL library from curl -; - -LIBRARY LIBCURL - -;DESCRIPTION 'curl libcurl - https://curl.haxx.se' - -EXPORTS - curl_easy_cleanup @ 1 ; - curl_easy_getinfo @ 2 ; - curl_easy_init @ 3 ; - curl_easy_perform @ 4 ; - curl_easy_setopt @ 5 ; - curl_escape @ 6 ; - curl_unescape @ 7; - curl_formfree @ 9 ; - curl_getdate @ 10 ; - curl_getenv @ 11 ; - curl_global_cleanup @ 12 ; - curl_global_init @ 13 ; - curl_slist_append @ 14 ; - curl_slist_free_all @ 15 ; - curl_version @ 16 ; - curl_maprintf @ 17 ; - curl_mfprintf @ 18 ; - curl_mprintf @ 19 ; - curl_msprintf @ 20 ; - curl_msnprintf @ 21 ; - curl_mvfprintf @ 22 ; - curl_strequal @ 23 ; - curl_strnequal @ 24 ; - curl_easy_duphandle @ 25 ; - curl_formadd @ 26 ; - curl_multi_init @ 27; - curl_multi_add_handle @ 28; - curl_multi_remove_handle @ 29; - curl_multi_fdset @ 30; - curl_multi_perform @ 31; - curl_multi_cleanup @ 32; - curl_multi_info_read @ 33; - curl_free @ 34; - curl_version_info @ 35; - curl_share_init @ 36; - curl_share_setopt @ 37; - curl_share_cleanup @ 38; - curl_global_init_mem @ 39; - curl_easy_strerror @ 40; - curl_multi_strerror @ 41; - curl_share_strerror @ 42; - curl_easy_reset @ 43; - curl_mvsnprintf @ 44 ; - diff --git a/contrib/curl/lib/libcurl.rc b/contrib/curl/lib/libcurl.rc index 50b365db..3316fba1 100644 --- a/contrib/curl/lib/libcurl.rc +++ b/contrib/curl/lib/libcurl.rc @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -44,14 +44,14 @@ BEGIN BEGIN BLOCK "040904b0" BEGIN - VALUE "CompanyName", "The cURL library, https://curl.haxx.se/\0" + VALUE "CompanyName", "The curl library, https://curl.haxx.se/\0" VALUE "FileDescription", "libcurl Shared Library\0" VALUE "FileVersion", LIBCURL_VERSION "\0" VALUE "InternalName", "libcurl\0" VALUE "OriginalFilename", "libcurl.dll\0" - VALUE "ProductName", "The cURL library\0" + VALUE "ProductName", "The curl library\0" VALUE "ProductVersion", LIBCURL_VERSION "\0" - VALUE "LegalCopyright", "© " LIBCURL_COPYRIGHT "\0" + VALUE "LegalCopyright", "\xa9 " LIBCURL_COPYRIGHT "\0" /* a9: Copyright symbol */ VALUE "License", "https://curl.haxx.se/docs/copyright.html\0" END END diff --git a/contrib/curl/lib/md4.c b/contrib/curl/lib/md4.c index 60f73a28..1bdc9f36 100644 --- a/contrib/curl/lib/md4.c +++ b/contrib/curl/lib/md4.c @@ -213,7 +213,8 @@ static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) unsigned long used, available; saved_lo = ctx->lo; - if((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->lo = (saved_lo + size) & 0x1fffffff; + if(ctx->lo < saved_lo) ctx->hi++; ctx->hi += (MD4_u32plus)size >> 29; diff --git a/contrib/curl/lib/md5.c b/contrib/curl/lib/md5.c index 84adb992..f2dc16c0 100644 --- a/contrib/curl/lib/md5.c +++ b/contrib/curl/lib/md5.c @@ -45,7 +45,7 @@ static void MD5_Init(MD5_CTX * ctx) } static void MD5_Update(MD5_CTX * ctx, - const unsigned char * input, + const unsigned char *input, unsigned int inputLen) { md5_update(ctx, inputLen, input); @@ -71,7 +71,7 @@ static void MD5_Init(MD5_CTX * ctx) } static void MD5_Update(MD5_CTX * ctx, - const unsigned char * input, + const unsigned char *input, unsigned int inputLen) { gcry_md_write(*ctx, input, inputLen); @@ -124,7 +124,7 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) CC_MD5_Final(digest, ctx); } -#elif defined(_WIN32) +#elif defined(_WIN32) && !defined(CURL_WINDOWS_APP) #include #include "curl_memory.h" @@ -402,7 +402,8 @@ static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size) unsigned long used, available; saved_lo = ctx->lo; - if((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->lo = (saved_lo + size) & 0x1fffffff; + if(ctx->lo < saved_lo) ctx->hi++; ctx->hi += (MD5_u32plus)size >> 29; diff --git a/contrib/curl/lib/memdebug.c b/contrib/curl/lib/memdebug.c index 1618bbaf..15e86616 100644 --- a/contrib/curl/lib/memdebug.c +++ b/contrib/curl/lib/memdebug.c @@ -90,7 +90,7 @@ struct memdebug { union { curl_off_t o; double d; - void * p; + void *p; } mem[1]; /* I'm hoping this is the thing with the strictest alignment * requirements. That also means we waste some space :-( */ @@ -119,7 +119,7 @@ void curl_memdebug(const char *logname) logfile = stderr; #ifdef MEMDEBUG_LOG_SYNC /* Flush the log file after every line so the log isn't lost in a crash */ - setvbuf(logfile, (char *)NULL, _IOLBF, 0); + setbuf(logfile, (char *)NULL); #endif } } diff --git a/contrib/curl/lib/mk-ca-bundle.pl b/contrib/curl/lib/mk-ca-bundle.pl index 5a1435c5..9574f1db 100644 --- a/contrib/curl/lib/mk-ca-bundle.pl +++ b/contrib/curl/lib/mk-ca-bundle.pl @@ -6,7 +6,7 @@ # * | (__| |_| | _ <| |___ # * \___|\___/|_| \_\_____| # * -# * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. +# * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. # * # * This software is licensed as described in the file COPYING, which # * you should have received as part of this distribution. The terms @@ -30,11 +30,11 @@ # dependency is the OpenSSL commandline tool for optional text listing. # Hacked by Guenter Knauf. # +use Encode; use Getopt::Std; use MIME::Base64; -use LWP::UserAgent; use strict; -use vars qw($opt_b $opt_d $opt_f $opt_h $opt_i $opt_l $opt_n $opt_p $opt_q $opt_s $opt_t $opt_u $opt_v $opt_w); +use vars qw($opt_b $opt_d $opt_f $opt_h $opt_i $opt_k $opt_l $opt_m $opt_n $opt_p $opt_q $opt_s $opt_t $opt_u $opt_v $opt_w); use List::Util; use Text::Wrap; my $MOD_SHA = "Digest::SHA"; @@ -43,18 +43,19 @@ if ($@) { $MOD_SHA = "Digest::SHA::PurePerl"; eval "require $MOD_SHA"; } +eval "require LWP::UserAgent"; my %urls = ( 'nss' => - 'http://hg.mozilla.org/projects/nss/raw-file/tip/lib/ckfw/builtins/certdata.txt', + 'https://hg.mozilla.org/projects/nss/raw-file/tip/lib/ckfw/builtins/certdata.txt', 'central' => - 'http://hg.mozilla.org/mozilla-central/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', + 'https://hg.mozilla.org/mozilla-central/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', 'aurora' => - 'http://hg.mozilla.org/releases/mozilla-aurora/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', + 'https://hg.mozilla.org/releases/mozilla-aurora/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', 'beta' => - 'http://hg.mozilla.org/releases/mozilla-beta/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', + 'https://hg.mozilla.org/releases/mozilla-beta/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', 'release' => - 'http://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', + 'https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt', ); $opt_d = 'release'; @@ -62,7 +63,7 @@ $opt_d = 'release'; # If the OpenSSL commandline is not in search path you can configure it here! my $openssl = 'openssl'; -my $version = '1.25'; +my $version = '1.27'; $opt_w = 76; # default base64 encoded lines length @@ -109,7 +110,7 @@ my @valid_signature_algorithms = ( $0 =~ s@.*(/|\\)@@; $Getopt::Std::STANDARD_HELP_VERSION = 1; -getopts('bd:fhilnp:qs:tuvw:'); +getopts('bd:fhiklmnp:qs:tuvw:'); if(!defined($opt_d)) { # to make plain "-d" use not cause warnings, and actually still work @@ -117,7 +118,16 @@ if(!defined($opt_d)) { } # Use predefined URL or else custom URL specified on command line. -my $url = ( defined( $urls{$opt_d} ) ) ? $urls{$opt_d} : $opt_d; +my $url; +if(defined($urls{$opt_d})) { + $url = $urls{$opt_d}; + if(!$opt_k && $url !~ /^https:\/\//i) { + die "The URL for '$opt_d' is not HTTPS. Use -k to override (insecure).\n"; + } +} +else { + $url = $opt_d; +} my $curl = `curl -V`; @@ -128,8 +138,8 @@ if ($opt_i) { print "Operating System Name : $^O\n"; print "Getopt::Std.pm Version : ${Getopt::Std::VERSION}\n"; print "MIME::Base64.pm Version : ${MIME::Base64::VERSION}\n"; - print "LWP::UserAgent.pm Version : ${LWP::UserAgent::VERSION}\n"; - print "LWP.pm Version : ${LWP::VERSION}\n"; + print "LWP::UserAgent.pm Version : ${LWP::UserAgent::VERSION}\n" if($LWP::UserAgent::VERSION); + print "LWP.pm Version : ${LWP::VERSION}\n" if($LWP::VERSION); print "Digest::SHA.pm Version : ${Digest::SHA::VERSION}\n" if ($Digest::SHA::VERSION); print "Digest::SHA::PurePerl.pm Version : ${Digest::SHA::PurePerl::VERSION}\n" if ($Digest::SHA::PurePerl::VERSION); print ("=" x 78 . "\n"); @@ -139,7 +149,7 @@ sub warning_message() { if ( $opt_d =~ m/^risk$/i ) { # Long Form Warning and Exit print "Warning: Use of this script may pose some risk:\n"; print "\n"; - print " 1) Using http is subject to man in the middle attack of certdata content\n"; + print " 1) If you use HTTP URLs they are subject to a man in the middle attack\n"; print " 2) Default to 'release', but more recent updates may be found in other trees\n"; print " 3) certdata.txt file format may change, lag time to update this script\n"; print " 4) Generally unwise to blindly trust CAs without manual review & verification\n"; @@ -153,14 +163,16 @@ sub warning_message() { } sub HELP_MESSAGE() { - print "Usage:\t${0} [-b] [-d] [-f] [-i] [-l] [-n] [-p] [-q] [-s] [-t] [-u] [-v] [-w] []\n"; + print "Usage:\t${0} [-b] [-d] [-f] [-i] [-k] [-l] [-n] [-p] [-q] [-s] [-t] [-u] [-v] [-w] []\n"; print "\t-b\tbackup an existing version of ca-bundle.crt\n"; print "\t-d\tspecify Mozilla tree to pull certdata.txt or custom URL\n"; print "\t\t Valid names are:\n"; print "\t\t ", join( ", ", map { ( $_ =~ m/$opt_d/ ) ? "$_ (default)" : "$_" } sort keys %urls ), "\n"; print "\t-f\tforce rebuild even if certdata.txt is current\n"; print "\t-i\tprint version info about used modules\n"; + print "\t-k\tallow URLs other than HTTPS, enable HTTP fallback (insecure)\n"; print "\t-l\tprint license info about certdata.txt\n"; + print "\t-m\tinclude meta data in output\n"; print "\t-n\tno download of certdata.txt (to use existing)\n"; print wrap("\t","\t\t", "-p\tlist of Mozilla trust purposes and levels for certificates to include in output. Takes the form of a comma separated list of purposes, a colon, and a comma separated list of levels. (default: $default_mozilla_trust_purposes:$default_mozilla_trust_levels)"), "\n"; print "\t\t Valid purposes are:\n"; @@ -224,33 +236,34 @@ sub parse_csv_param($$@) { return @values; } -sub sha1 { +sub sha256 { my $result; if ($Digest::SHA::VERSION || $Digest::SHA::PurePerl::VERSION) { open(FILE, $_[0]) or die "Can't open '$_[0]': $!"; binmode(FILE); - $result = $MOD_SHA->new(1)->addfile(*FILE)->hexdigest; + $result = $MOD_SHA->new(256)->addfile(*FILE)->hexdigest; close(FILE); } else { # Use OpenSSL command if Perl Digest::SHA modules not available - $result = (split(/ |\r|\n/,`$openssl dgst -sha1 $_[0]`))[1]; + $result = `"$openssl" dgst -r -sha256 "$_[0]"`; + $result =~ s/^([0-9a-f]{64}) .+/$1/is; } return $result; } -sub oldsha1 { - my $sha1 = ""; +sub oldhash { + my $hash = ""; open(C, "<$_[0]") || return 0; while() { chomp; - if($_ =~ /^\#\# SHA1: (.*)/) { - $sha1 = $1; + if($_ =~ /^\#\# SHA256: (.*)/) { + $hash = $1; last; } } close(C); - return $sha1; + return $hash; } if ( $opt_p !~ m/:/ ) { @@ -282,39 +295,72 @@ my $stdout = $crt eq '-'; my $resp; my $fetched; -my $oldsha1 = oldsha1($crt); +my $oldhash = oldhash($crt); -report "SHA1 of old file: $oldsha1"; +report "SHA256 of old file: $oldhash"; -report "Downloading '$txt' ..."; +if(!$opt_n) { + report "Downloading $txt ..."; -if($curl && !$opt_n) { - my $https = $url; - $https =~ s/^http:/https:/; - report "Get certdata over HTTPS with curl!"; - my $quiet = $opt_q ? "-s" : ""; - my @out = `curl -w %{response_code} $quiet -O $https`; - if(@out && $out[0] == 200) { - $fetched = 1; - } else { - report "Failed downloading HTTPS with curl, trying HTTP with LWP"; + # If we have an HTTPS URL then use curl + if($url =~ /^https:\/\//i) { + if($curl) { + if($curl =~ /^Protocols:.* https( |$)/m) { + report "Get certdata with curl!"; + my $proto = !$opt_k ? "--proto =https" : ""; + my $quiet = $opt_q ? "-s" : ""; + my @out = `curl -w %{response_code} $proto $quiet -o "$txt" "$url"`; + if(@out && $out[0] == 200) { + $fetched = 1; + report "Downloaded $txt"; + } + else { + report "Failed downloading via HTTPS with curl"; + if(-e $txt && !unlink($txt)) { + report "Failed to remove '$txt': $!"; + } + } + } + else { + report "curl lacks https support"; + } + } + else { + report "curl not found"; + } } -} -unless ($fetched || ($opt_n and -e $txt)) { - my $ua = new LWP::UserAgent(agent => "$0/$version"); - $ua->env_proxy(); - $resp = $ua->mirror($url, $txt); - if ($resp && $resp->code eq '304') { - report "Not modified"; - exit 0 if -e $crt && !$opt_f; - } else { + # If nothing was fetched then use LWP + if(!$fetched) { + if($url =~ /^https:\/\//i) { + report "Falling back to HTTP"; + $url =~ s/^https:\/\//http:\/\//i; + } + if(!$opt_k) { + report "URLs other than HTTPS are disabled by default, to enable use -k"; + exit 1; + } + report "Get certdata with LWP!"; + if(!defined(${LWP::UserAgent::VERSION})) { + report "LWP is not available (LWP::UserAgent not found)"; + exit 1; + } + my $ua = new LWP::UserAgent(agent => "$0/$version"); + $ua->env_proxy(); + $resp = $ua->mirror($url, $txt); + if($resp && $resp->code eq '304') { + report "Not modified"; + exit 0 if -e $crt && !$opt_f; + } + else { $fetched = 1; - } - if( !$resp || $resp->code !~ /^(?:200|304)$/ ) { + report "Downloaded $txt"; + } + if(!$resp || $resp->code !~ /^(?:200|304)$/) { report "Unable to download latest data: " . ($resp? $resp->code . ' - ' . $resp->message : "LWP failed"); exit 1 if -e $crt || ! -r $txt; + } } } @@ -327,14 +373,14 @@ if(!$filedate) { } # get the hash from the download file -my $newsha1= sha1($txt); +my $newhash= sha256($txt); -if(!$opt_f && $oldsha1 eq $newsha1) { +if(!$opt_f && $oldhash eq $newhash) { report "Downloaded file identical to previous run\'s source file. Exiting"; exit; } -report "SHA1 of new file: $newsha1"; +report "SHA256 of new file: $newhash"; my $currentdate = scalar gmtime($filedate); @@ -348,7 +394,7 @@ print CRT <) { @@ -383,11 +430,15 @@ while () { last if (/\*\*\*\*\* END LICENSE BLOCK \*\*\*\*\*/); } } - next if /^#|^\s*$/; - chomp; - if (/^CVS_ID\s+\"(.*)\"/) { - print CRT "# $1\n"; + elsif(/^# (Issuer|Serial Number|Subject|Not Valid Before|Not Valid After |Fingerprint \(MD5\)|Fingerprint \(SHA1\)):/) { + push @precert, $_; + next; } + elsif(/^#|^\s*$/) { + undef @precert; + next; + } + chomp; # this is a match for the start of a certificate if (/^CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE/) { @@ -436,8 +487,8 @@ while () { . $encoded . "-----END CERTIFICATE-----\n"; print CRT "\n$caname\n"; - - my $maxStringLength = length($caname); + print CRT @precert if($opt_m); + my $maxStringLength = length(decode('UTF-8', $caname, Encode::FB_CROAK)); if ($opt_t) { foreach my $key (keys %trust_purposes_by_level) { my $string = $key . ": " . join(", ", @{$trust_purposes_by_level{$key}}); @@ -479,7 +530,9 @@ while () { $certnum ++; $start_of_cert = 0; } + undef @precert; } + } close(TXT) or die "Couldn't close $txt: $!\n"; close(CRT) or die "Couldn't close $crt.~: $!\n"; @@ -495,5 +548,7 @@ unless( $stdout ) { } rename "$crt.~", $crt or die "Failed to rename $crt.~ to $crt: $!\n"; } -unlink $txt if ($opt_u); +if($opt_u && -e $txt && !unlink($txt)) { + report "Failed to remove $txt: $!\n"; +} report "Done ($certnum CA certs processed, $skipnum skipped)."; diff --git a/contrib/curl/lib/mk-ca-bundle.vbs b/contrib/curl/lib/mk-ca-bundle.vbs index 27b4aee5..da7a577e 100644 --- a/contrib/curl/lib/mk-ca-bundle.vbs +++ b/contrib/curl/lib/mk-ca-bundle.vbs @@ -26,20 +26,36 @@ '* Hacked by Guenter Knauf '*************************************************************************** Option Explicit -Const myVersion = "0.3.9" +Const myVersion = "0.4.0" -Const myUrl = "http://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt" -Const myOpenssl = "openssl.exe" +Const myUrl = "https://hg.mozilla.org/releases/mozilla-release/raw-file/default/security/nss/lib/ckfw/builtins/certdata.txt" -Const myCdSavF = FALSE ' Flag: save downloaded data to file certdata.txt +Const myOpenSSL = "openssl.exe" +Dim myUseOpenSSL +myUseOpenSSL = TRUE ' Flag: TRUE to use OpenSSL. If TRUE and is not + ' found then a warning is shown before continuing. + +Const myCdSavF = TRUE ' Flag: save downloaded data to file certdata.txt Const myCaBakF = TRUE ' Flag: backup existing ca-bundle certificate Const myAskLiF = TRUE ' Flag: display certdata.txt license agreement -Const myAskTiF = TRUE ' Flag: ask to include certificate text info Const myWrapLe = 76 ' Default length of base64 output lines +' cert info code doesn't work properly with any recent openssl, leave disabled. +' Also: we want our certificate output by default to be as similar as possible +' to mk-ca-bundle.pl and setting this TRUE changes the base64 width to +' OpenSSL's built-in default width, which is not the same as mk-ca-bundle.pl. +Const myAskTiF = FALSE ' Flag: ask to include certificate text info + +' '******************* Nothing to configure below! ******************* +' +Const adTypeBinary = 1 +Const adTypeText = 2 +Const adSaveCreateNotExist = 1 +Const adSaveCreateOverWrite = 2 Dim objShell, objNetwork, objFSO, objHttp -Dim myBase, mySelf, myFh, myTmpFh, myCdData, myCdFile, myCaFile, myTmpName, myBakNum, myOptTxt, i +Dim myBase, mySelf, myStream, myTmpFh, myCdData, myCdFile +Dim myCaFile, myTmpName, myBakNum, myOptTxt, i Set objNetwork = WScript.CreateObject("WScript.Network") Set objShell = WScript.CreateObject("WScript.Shell") Set objFSO = WScript.CreateObject("Scripting.FileSystemObject") @@ -47,14 +63,60 @@ Set objHttp = WScript.CreateObject("WinHttp.WinHttpRequest.5.1") If objHttp Is Nothing Then Set objHttp = WScript.CreateObject("WinHttp.WinHttpRequest") myBase = Left(WScript.ScriptFullName, InstrRev(WScript.ScriptFullName, "\")) mySelf = Left(WScript.ScriptName, InstrRev(WScript.ScriptName, ".") - 1) & " " & myVersion + myCdFile = Mid(myUrl, InstrRev(myUrl, "/") + 1) myCaFile = "ca-bundle.crt" -myTmpName = InputBox("Enter output filename:", mySelf, myCaFile) -If Not (myTmpName = "") Then - myCaFile = myTmpName +myTmpName = InputBox("It will take a minute to download and parse the " & _ + "certificate data." & _ + vbLf & vbLf & _ + "Please enter the output filename:", mySelf, myCaFile) +If (myTmpName = "") Then + WScript.Quit 1 End If -' Lets ignore SSL invalid cert errors -objHttp.Option(4) = 256 + 512 + 4096 + 8192 +myCaFile = myTmpName +If (myCdFile = "") Then + MsgBox("URL does not contain filename!"), vbCritical, mySelf + WScript.Quit 1 +End If + +' Don't use OpenSSL if it's not present. +If (myUseOpenSSL = TRUE) Then + Dim errnum + + On Error Resume Next + Call objShell.Run("""" & myOpenSSL & """ version", 0, TRUE) + errnum = Err.Number + On Error GoTo 0 + + If Not (errnum = 0) Then + myUseOpenSSL = FALSE + MsgBox("OpenSSL was not found so the certificate bundle will not " & _ + "include the SHA256 hash of the raw certificate data file " & _ + "that was used to generate the certificates in the bundle. " & _ + vbLf & vbLf & _ + "This does not have any effect on the certificate output, " & _ + "so this script will continue." & _ + vbLf & vbLf & _ + "If you want to set a custom location for OpenSSL or disable " & _ + "this message then edit the variables at the start of the " & _ + "script."), vbInformation, mySelf + End If +End If + +If (myAskTiF = TRUE) And (myUseOpenSSL = TRUE) Then + If (6 = objShell.PopUp("Do you want to include text information about " & _ + "each certificate?" & vbLf & _ + "(Requires OpenSSL.exe in the current directory " & _ + "or search path)",, _ + mySelf, vbQuestion + vbYesNo + vbDefaultButton2)) Then + myOptTxt = TRUE + Else + myOptTxt = FALSE + End If +End If + +' Uncomment the line below to ignore SSL invalid cert errors +' objHttp.Option(4) = 256 + 512 + 4096 + 8192 objHttp.SetTimeouts 0, 5000, 10000, 10000 objHttp.Open "GET", myUrl, FALSE objHttp.setRequestHeader "User-Agent", WScript.ScriptName & "/" & myVersion @@ -63,15 +125,13 @@ If Not (objHttp.Status = 200) Then MsgBox("Failed to download '" & myCdFile & "': " & objHttp.Status & " - " & objHttp.StatusText), vbCritical, mySelf WScript.Quit 1 End If -' Convert data from ResponseBody instead of using ResponseText because of UTF-8 -myCdData = ConvertBinaryData(objHttp.ResponseBody) -Set objHttp = Nothing ' Write received data to file if enabled If (myCdSavF = TRUE) Then - Set myFh = objFSO.OpenTextFile(myCdFile, 2, TRUE) - myFh.Write myCdData - myFh.Close + Call SaveBinaryData(myCdFile, objHttp.ResponseBody) End If +' Convert data from ResponseBody instead of using ResponseText because of UTF-8 +myCdData = ConvertBinaryToUTF8(objHttp.ResponseBody) +Set objHttp = Nothing ' Backup exitsing ca-bundle certificate file If (myCaBakF = TRUE) Then If objFSO.FileExists(myCaFile) Then @@ -86,15 +146,7 @@ If (myCaBakF = TRUE) Then myTmpFh.Move myBakFile End If End If -If (myAskTiF = TRUE) Then - If (6 = objShell.PopUp("Do you want to include text information about each certificate?" & vbLf & _ - "(requires OpenSSL commandline in current directory or in search path)",, _ - mySelf, vbQuestion + vbYesNo + vbDefaultButton2)) Then - myOptTxt = TRUE - Else - myOptTxt = FALSE - End If -End If + ' Process the received data Dim myLines, myPattern, myInsideCert, myInsideLicense, myLicenseText, myNumCerts, myNumSkipped Dim myLabel, myOctets, myData, myPem, myRev, myUntrusted, j @@ -102,23 +154,33 @@ myNumSkipped = 0 myNumCerts = 0 myData = "" myLines = Split(myCdData, vbLf, -1) -Set myFh = objFSO.OpenTextFile(myCaFile, 2, TRUE) -myFh.Write "##" & vbLf -myFh.Write "## " & myCaFile & " -- Bundle of CA Root Certificates" & vbLf -myFh.Write "##" & vbLf -myFh.Write "## Converted at: " & Now & vbLf -myFh.Write "##" & vbLf -myFh.Write "## This is a bundle of X.509 certificates of public Certificate Authorities" & vbLf -myFh.Write "## (CA). These were automatically extracted from Mozilla's root certificates" & vbLf -myFh.Write "## file (certdata.txt). This file can be found in the mozilla source tree:" & vbLf -myFh.Write "## '/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt'" & vbLf -myFh.Write "##" & vbLf -myFh.Write "## It contains the certificates in PEM format and therefore" & vbLf -myFh.Write "## can be directly used with curl / libcurl / php_curl, or with" & vbLf -myFh.Write "## an Apache+mod_ssl webserver for SSL client authentication." & vbLf -myFh.Write "## Just configure this file as the SSLCACertificateFile." & vbLf -myFh.Write "##" & vbLf -myFh.Write vbLf +Set myStream = CreateObject("ADODB.Stream") +myStream.Open +myStream.Type = adTypeText +myStream.Charset = "utf-8" +myStream.WriteText "##" & vbLf & _ + "## Bundle of CA Root Certificates" & vbLf & _ + "##" & vbLf & _ + "## Certificate data from Mozilla as of: " & _ + ConvertDateToString(LocalDateToUTC(Now)) & " GMT" & vbLf & _ + "##" & vbLf & _ + "## This is a bundle of X.509 certificates of public Certificate Authorities" & vbLf & _ + "## (CA). These were automatically extracted from Mozilla's root certificates" & vbLf & _ + "## file (certdata.txt). This file can be found in the mozilla source tree:" & vbLf & _ + "## " & myUrl & vbLf & _ + "##" & vbLf & _ + "## It contains the certificates in PEM format and therefore" & vbLf & _ + "## can be directly used with curl / libcurl / php_curl, or with" & vbLf & _ + "## an Apache+mod_ssl webserver for SSL client authentication." & vbLf & _ + "## Just configure this file as the SSLCACertificateFile." & vbLf & _ + "##" & vbLf & _ + "## Conversion done with mk-ca-bundle.vbs version " & myVersion & "." & vbLf +If (myCdSavF = TRUE) And (myUseOpenSSL = TRUE) Then + myStream.WriteText "## SHA256: " & FileSHA256(myCdFile) & vbLf +End If +myStream.WriteText "##" & vbLf & vbLf + +myStream.WriteText vbLf For i = 0 To UBound(myLines) If InstrRev(myLines(i), "CKA_LABEL ") Then myPattern = "^CKA_LABEL\s+[A-Z0-9]+\s+""(.+?)""" @@ -136,13 +198,13 @@ For i = 0 To UBound(myLines) If (myUntrusted = TRUE) Then myNumSkipped = myNumSkipped + 1 Else - myFh.Write myLabel & vbLf - myFh.Write String(Len(myLabel), "=") & vbLf + myStream.WriteText myLabel & vbLf + myStream.WriteText String(Len(myLabel), "=") & vbLf myPem = "-----BEGIN CERTIFICATE-----" & vbLf & _ Base64Encode(myData) & vbLf & _ "-----END CERTIFICATE-----" & vbLf If (myOptTxt = FALSE) Then - myFh.Write myPem & vbLf + myStream.WriteText myPem & vbLf Else Dim myCmd, myRval, myTmpIn, myTmpOut myTmpIn = objFSO.GetSpecialFolder(2).Path & "\" & objFSO.GetTempName @@ -150,8 +212,8 @@ For i = 0 To UBound(myLines) Set myTmpFh = objFSO.OpenTextFile(myTmpIn, 2, TRUE) myTmpFh.Write myPem myTmpFh.Close - myCmd = myOpenssl & " x509 -md5 -fingerprint -text -inform PEM" & _ - " -in " & myTmpIn & " -out " & myTmpOut + myCmd = """" & myOpenSSL & """ x509 -md5 -fingerprint -text " & _ + "-inform PEM -in " & myTmpIn & " -out " & myTmpOut myRval = objShell.Run (myCmd, 0, TRUE) objFSO.DeleteFile myTmpIn, TRUE If Not (myRval = 0) Then @@ -160,7 +222,7 @@ For i = 0 To UBound(myLines) WScript.Quit 3 End If Set myTmpFh = objFSO.OpenTextFile(myTmpOut, 1) - myFh.Write myTmpFh.ReadAll & vbLf + myStream.WriteText myTmpFh.ReadAll & vbLf myTmpFh.Close objFSO.DeleteFile myTmpOut, TRUE End If @@ -176,7 +238,7 @@ For i = 0 To UBound(myLines) If InstrRev(myLines(i), "CVS_ID ") Then myPattern = "^CVS_ID\s+""(.+?)""" myRev = RegExprFirst(myPattern, myLines(i)) - myFh.Write "# " & myRev & vbLf & vbLf + myStream.WriteText "# " & myRev & vbLf & vbLf End If If InstrRev(myLines(i), "CKA_VALUE MULTILINE_OCTAL") Then myInsideCert = TRUE @@ -187,7 +249,7 @@ For i = 0 To UBound(myLines) myInsideLicense = TRUE End If If (myInsideLicense = TRUE) Then - myFh.Write myLines(i) & vbLf + myStream.WriteText myLines(i) & vbLf myLicenseText = myLicenseText & Mid(myLines(i), 2) & vbLf End If If InstrRev(myLines(i), "***** END LICENSE BLOCK *****") Then @@ -196,28 +258,54 @@ For i = 0 To UBound(myLines) If Not (6 = objShell.PopUp(myLicenseText & vbLf & _ "Do you agree to the license shown above (required to proceed) ?",, _ mySelf, vbQuestion + vbYesNo + vbDefaultButton1)) Then - myFh.Close + myStream.Close objFSO.DeleteFile myCaFile, TRUE WScript.Quit 2 End If End If End If Next -myFh.Close + +' To stop the UTF-8 BOM from being written the stream has to be copied and +' then saved as binary. +Dim myCopy +Set myCopy = CreateObject("ADODB.Stream") +myCopy.Type = adTypeBinary +myCopy.Open +myStream.Position = 3 ' Skip UTF-8 BOM +myStream.CopyTo myCopy +myCopy.SaveToFile myCaFile, adSaveCreateOverWrite +myCopy.Close +myStream.Close +Set myCopy = Nothing +Set myStream = Nothing + +' Done objShell.PopUp "Done (" & myNumCerts & " CA certs processed, " & myNumSkipped & _ " untrusted skipped).", 20, mySelf, vbInformation WScript.Quit 0 -Function ConvertBinaryData(arrBytes) +Function ConvertBinaryToUTF8(arrBytes) Dim objStream Set objStream = CreateObject("ADODB.Stream") objStream.Open - objStream.Type = 1 + objStream.Type = adTypeBinary objStream.Write arrBytes objStream.Position = 0 - objStream.Type = 2 - objStream.Charset = "ascii" - ConvertBinaryData = objStream.ReadText + objStream.Type = adTypeText + objStream.Charset = "utf-8" + ConvertBinaryToUTF8 = objStream.ReadText + Set objStream = Nothing +End Function + +Function SaveBinaryData(filename, data) + Dim objStream + Set objStream = CreateObject("ADODB.Stream") + objStream.Type = adTypeBinary + objStream.Open + objStream.Write data + objStream.SaveToFile filename, adSaveCreateOverWrite + objStream.Close Set objStream = Nothing End Function @@ -283,4 +371,61 @@ Function MyASC(OneChar) If OneChar = "" Then MyASC = 0 Else MyASC = Asc(OneChar) End Function +' Return the date in the same format as perl to match mk-ca-bundle.pl output: +' Wed Sep 7 03:12:05 2016 +Function ConvertDateToString(input) + Dim output + output = WeekDayName(WeekDay(input), TRUE) & " " & _ + MonthName(Month(input), TRUE) & " " + If (Len(Day(input)) = 1) Then + output = output & " " + End If + output = output & _ + Day(input) & " " & _ + FormatDateTime(input, vbShortTime) & ":" + If (Len(Second(input)) = 1) Then + output = output & "0" + End If + output = output & _ + Second(input) & " " & _ + Year(input) + ConvertDateToString = output +End Function +' Convert local Date to UTC. Microsoft says: +' Use Win32_ComputerSystem CurrentTimeZone property, because it automatically +' adjusts the Time Zone bias for daylight saving time; Win32_Time Zone Bias +' property does not. +' https://msdn.microsoft.com/en-us/library/windows/desktop/ms696015.aspx +Function LocalDateToUTC(localdate) + Dim item, offset + For Each item In GetObject("winmgmts:").InstancesOf("Win32_ComputerSystem") + offset = item.CurrentTimeZone ' the offset in minutes + Next + If (offset < 0) Then + LocalDateToUTC = DateAdd("n", ABS(offset), localdate) + Else + LocalDateToUTC = DateAdd("n", -ABS(offset), localdate) + End If + 'objShell.PopUp LocalDateToUTC +End Function + +Function FileSHA256(filename) + Dim cmd, rval, tmpOut, tmpFh + if (myUseOpenSSL = TRUE) Then + tmpOut = objFSO.GetSpecialFolder(2).Path & "\" & objFSO.GetTempName + cmd = """" & myOpenSSL & """ dgst -r -sha256 -out """ & tmpOut & """ """ & filename & """" + rval = objShell.Run(cmd, 0, TRUE) + If Not (rval = 0) Then + MsgBox("Failed to get sha256 of """ & filename & """ with OpenSSL commandline!"), vbCritical, mySelf + objFSO.DeleteFile tmpOut, TRUE + WScript.Quit 3 + End If + Set tmpFh = objFSO.OpenTextFile(tmpOut, 1) + FileSHA256 = RegExprFirst("^([0-9a-f]{64}) .+", tmpFh.ReadAll) + tmpFh.Close + objFSO.DeleteFile tmpOut, TRUE + Else + FileSHA256 = "" + End If +End Function diff --git a/contrib/curl/lib/mprintf.c b/contrib/curl/lib/mprintf.c index 73f854bc..e4270abe 100644 --- a/contrib/curl/lib/mprintf.c +++ b/contrib/curl/lib/mprintf.c @@ -92,7 +92,8 @@ # define mp_uintmax_t unsigned long #endif -#define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */ +#define BUFFSIZE 326 /* buffer for long-to-str and float-to-str calcs, should + fit negative DBL_MAX (317 letters) */ #define MAX_PARAMETERS 128 /* lame static limit */ #ifdef __AMIGA__ @@ -227,10 +228,12 @@ static bool dprintf_IsQualifierNoDollar(const char *fmt) * Create an index with the type of each parameter entry and its * value (may vary in size) * + * Returns zero on success. + * ******************************************************************/ -static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, - va_list arglist) +static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, + va_list arglist) { char *fmt = (char *)format; int param_num = 0; @@ -301,7 +304,6 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, flags |= FLAGS_ALT; break; case '.': - flags |= FLAGS_PREC; if('*' == *fmt) { /* The precision is picked from a specified parameter */ @@ -393,6 +395,10 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, i = this_param - 1; + if((i < 0) || (i >= MAX_PARAMETERS)) + /* out of allowed range */ + return 1; + switch (*fmt) { case 'S': flags |= FLAGS_ALT; @@ -496,7 +502,7 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, (mp_intmax_t)va_arg(arglist, int); } - switch (vto[i].type) { + switch(vto[i].type) { case FORMAT_STRING: vto[i].data.str = va_arg(arglist, char *); break; @@ -549,7 +555,7 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, } } - return max_param; + return 0; } @@ -587,7 +593,8 @@ static int dprintf_formatf( char *workend = &work[sizeof(work) - 2]; /* Do the actual %-code parsing */ - dprintf_Pass1(format, vto, endpos, ap_save); + if(dprintf_Pass1(format, vto, endpos, ap_save)) + return -1; end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1() created for us */ @@ -685,7 +692,7 @@ static int dprintf_formatf( is_alt = (p->flags & FLAGS_ALT) ? 1 : 0; - switch (p->type) { + switch(p->type) { case FORMAT_INT: num = p->data.num.as_unsigned; if(p->flags & FLAGS_CHAR) { @@ -910,12 +917,25 @@ static int dprintf_formatf( *fptr = 0; if(width >= 0) { + if(width >= (long)sizeof(work)) + width = sizeof(work)-1; /* RECURSIVE USAGE */ len = curl_msnprintf(fptr, left, "%ld", width); fptr += len; left -= len; } if(prec >= 0) { + /* for each digit in the integer part, we can have one less + precision */ + size_t maxprec = sizeof(work) - 2; + double val = p->data.dnum; + while(val >= 10.0) { + val /= 10; + maxprec--; + } + + if(prec > (long)maxprec) + prec = (long)maxprec-1; /* RECURSIVE USAGE */ len = curl_msnprintf(fptr, left, ".%ld", prec); fptr += len; @@ -935,7 +955,9 @@ static int dprintf_formatf( /* NOTE NOTE NOTE!! Not all sprintf implementations return number of output characters */ (sprintf)(work, formatbuf, p->data.dnum); - +#ifdef CURLDEBUG + assert(strlen(work) <= sizeof(work)); +#endif for(fptr=work; *fptr; fptr++) OUTCHAR(*fptr); } @@ -992,7 +1014,7 @@ int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, info.max = maxlength; retcode = dprintf_formatf(&info, addbyter, format, ap_save); - if(info.max) { + if((retcode != -1) && info.max) { /* we terminate this with a zero byte */ if(info.max == info.length) /* we're at maximum, scrap the last letter */ @@ -1029,16 +1051,19 @@ static int alloc_addbyter(int output, FILE *data) infop->len =0; } else if(infop->len+1 >= infop->alloc) { - char *newptr; + char *newptr = NULL; + size_t newsize = infop->alloc*2; - newptr = realloc(infop->buffer, infop->alloc*2); + /* detect wrap-around or other overflow problems */ + if(newsize > infop->alloc) + newptr = realloc(infop->buffer, newsize); if(!newptr) { infop->fail = 1; return -1; /* fail */ } infop->buffer = newptr; - infop->alloc *= 2; + infop->alloc = newsize; } infop->buffer[ infop->len ] = outc; diff --git a/contrib/curl/lib/multi.c b/contrib/curl/lib/multi.c index 7e2725ba..bb31dc1d 100644 --- a/contrib/curl/lib/multi.c +++ b/contrib/curl/lib/multi.c @@ -42,6 +42,8 @@ #include "multihandle.h" #include "pipeline.h" #include "sigpipe.h" +#include "vtls/vtls.h" +#include "connect.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -61,15 +63,15 @@ #define CURL_MULTI_HANDLE 0x000bab1e #define GOOD_MULTI_HANDLE(x) \ - ((x) && (((struct Curl_multi *)(x))->type == CURL_MULTI_HANDLE)) + ((x) && (x)->type == CURL_MULTI_HANDLE) static void singlesocket(struct Curl_multi *multi, - struct SessionHandle *data); + struct Curl_easy *data); static int update_timer(struct Curl_multi *multi); static CURLMcode add_next_timeout(struct timeval now, struct Curl_multi *multi, - struct SessionHandle *d); + struct Curl_easy *d); static CURLMcode multi_timeout(struct Curl_multi *multi, long *timeout_ms); @@ -100,10 +102,10 @@ static const char * const statename[]={ static void multi_freetimeout(void *a, void *b); /* function pointer called once when switching TO a state */ -typedef void (*init_multistate_func)(struct SessionHandle *data); +typedef void (*init_multistate_func)(struct Curl_easy *data); /* always use this function to change state, to make debugging easier */ -static void mstate(struct SessionHandle *data, CURLMstate state +static void mstate(struct Curl_easy *data, CURLMstate state #ifdef DEBUGBUILD , int lineno #endif @@ -162,7 +164,7 @@ static void mstate(struct SessionHandle *data, CURLMstate state */ struct Curl_sh_entry { - struct SessionHandle *easy; + struct Curl_easy *easy; int action; /* what action READ/WRITE this socket waits for */ curl_socket_t socket; /* mainly to ease debugging */ void *socketp; /* settable by users with curl_multi_assign() */ @@ -185,7 +187,7 @@ static struct Curl_sh_entry *sh_getentry(struct curl_hash *sh, /* make sure this socket is present in the hash for this handle */ static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh, curl_socket_t s, - struct SessionHandle *data) + struct Curl_easy *data) { struct Curl_sh_entry *there = sh_getentry(sh, s); struct Curl_sh_entry *check; @@ -334,7 +336,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ /* -1 means it not set by user, use the default value */ multi->maxconnects = -1; - return (CURLM *) multi; + return multi; error: @@ -350,25 +352,23 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ return NULL; } -CURLM *curl_multi_init(void) +struct Curl_multi *curl_multi_init(void) { return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE, CURL_CONNECTION_HASH_SIZE); } -CURLMcode curl_multi_add_handle(CURLM *multi_handle, - CURL *easy_handle) +CURLMcode curl_multi_add_handle(struct Curl_multi *multi, + struct Curl_easy *data) { struct curl_llist *timeoutlist; - struct Curl_multi *multi = (struct Curl_multi *)multi_handle; - struct SessionHandle *data = (struct SessionHandle *)easy_handle; /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; /* Verify that we got a somewhat good easy handle too */ - if(!GOOD_EASY_HANDLE(easy_handle)) + if(!GOOD_EASY_HANDLE(data)) return CURLM_BAD_EASY_HANDLE; /* Prevent users from adding same easy handle more than once and prevent @@ -417,14 +417,14 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, data->state.conn_cache = &multi->conn_cache; /* This adds the new entry at the 'end' of the doubly-linked circular - list of SessionHandle structs to try and maintain a FIFO queue so + list of Curl_easy structs to try and maintain a FIFO queue so the pipelined requests are in order. */ /* We add this new entry last in the list. */ data->next = NULL; /* end of the line */ if(multi->easyp) { - struct SessionHandle *last = multi->easylp; + struct Curl_easy *last = multi->easylp; last->next = data; data->prev = last; multi->easylp = data; /* the new last node */ @@ -435,8 +435,8 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, multi->easylp = multi->easyp = data; /* both first and last */ } - /* make the SessionHandle refer back to this multi handle */ - data->multi = multi_handle; + /* make the Curl_easy refer back to this multi handle */ + data->multi = multi; /* Set the timeout for this handle to expire really soon so that it will be taken care of even when this handle is added in the midst of operation @@ -444,7 +444,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, sockets that time-out or have actions will be dealt with. Since this handle has no action yet, we make sure it times out to get things to happen. */ - Curl_expire(data, 1); + Curl_expire(data, 0); /* increase the node-counter */ multi->num_easy++; @@ -464,6 +464,14 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, handle is added */ memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall)); + /* The closure handle only ever has default timeouts set. To improve the + state somewhat we clone the timeouts from each added handle so that the + closure handle always has the same timeouts as the most recently added + easy handle. */ + multi->closure_handle->set.timeout = data->set.timeout; + multi->closure_handle->set.server_response_timeout = + data->set.server_response_timeout; + update_timer(multi); return CURLM_OK; } @@ -487,7 +495,7 @@ static void debug_print_sock_hash(void *p) /* Mark the connection as 'idle', or close it if the cache is full. Returns TRUE if the connection is kept, or FALSE if it was closed. */ static bool -ConnectionDone(struct SessionHandle *data, struct connectdata *conn) +ConnectionDone(struct Curl_easy *data, struct connectdata *conn) { /* data->multi->maxconnects can be negative, deal with it. */ size_t maxconnects = @@ -523,7 +531,7 @@ static CURLcode multi_done(struct connectdata **connp, { CURLcode result; struct connectdata *conn; - struct SessionHandle *data; + struct Curl_easy *data; DEBUGASSERT(*connp); @@ -571,12 +579,12 @@ static CURLcode multi_done(struct connectdata **connp, result = CURLE_ABORTED_BY_CALLBACK; } - if((!premature && - conn->send_pipe->size + conn->recv_pipe->size != 0 && - !data->set.reuse_forbid && - !conn->bits.close)) { + if(conn->send_pipe->size + conn->recv_pipe->size != 0 && + !data->set.reuse_forbid && + !conn->bits.close) { /* Stop if pipeline is not empty and we do not have to close connection. */ + data->easy_conn = NULL; DEBUGF(infof(data, "Connection still in use, no more multi_done now!\n")); return CURLE_OK; } @@ -630,7 +638,10 @@ static CURLcode multi_done(struct connectdata **connp, infof(data, "Connection #%ld to host %s left intact\n", conn->connection_id, - conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname); + conn->bits.socksproxy ? conn->socks_proxy.host.dispname : + conn->bits.httpproxy ? conn->http_proxy.host.dispname : + conn->bits.conn_to_host ? conn->conn_to_host.dispname : + conn->host.dispname); } else data->state.lastconnect = NULL; @@ -645,12 +656,10 @@ static CURLcode multi_done(struct connectdata **connp, return result; } -CURLMcode curl_multi_remove_handle(CURLM *multi_handle, - CURL *curl_handle) +CURLMcode curl_multi_remove_handle(struct Curl_multi *multi, + struct Curl_easy *data) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct SessionHandle *easy = curl_handle; - struct SessionHandle *data = easy; + struct Curl_easy *easy = data; bool premature; bool easy_owns_conn; struct curl_llist_element *e; @@ -660,7 +669,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, return CURLM_BAD_HANDLE; /* Verify that we got a somewhat good easy handle too */ - if(!GOOD_EASY_HANDLE(curl_handle)) + if(!GOOD_EASY_HANDLE(data)) return CURLM_BAD_EASY_HANDLE; /* Prevent users from trying to remove same easy handle more than once */ @@ -689,7 +698,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, /* If the handle is in a pipeline and has started sending off its request but not received its response yet, we need to close connection. */ - connclose(data->easy_conn, "Removed with partial response"); + streamclose(data->easy_conn, "Removed with partial response"); /* Set connection owner so that the DONE function closes it. We can safely do this here since connection is killed. */ data->easy_conn->data = easy; @@ -699,7 +708,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, /* The timer must be shut down before data->multi is set to NULL, else the timenode will remain in the splay tree after curl_easy_cleanup is called. */ - Curl_expire(data, 0); + Curl_expire_clear(data); if(data->dns.hostcachetype == HCACHE_MULTI) { /* stop using the multi handle's DNS cache */ @@ -791,7 +800,7 @@ bool Curl_pipeline_wanted(const struct Curl_multi *multi, int bits) return (multi && (multi->pipelining & bits)) ? TRUE : FALSE; } -void Curl_multi_handlePipeBreak(struct SessionHandle *data) +void Curl_multi_handlePipeBreak(struct Curl_easy *data) { data->easy_conn = NULL; } @@ -807,6 +816,11 @@ static int waitconnect_getsock(struct connectdata *conn, if(!numsocks) return GETSOCK_BLANK; +#ifdef USE_SSL + if(CONNECT_FIRSTSOCKET_PROXY_SSL()) + return Curl_ssl_getsock(conn, sock, numsocks); +#endif + for(i=0; i<2; i++) { if(conn->tempsock[i] != CURL_SOCKET_BAD) { sock[s] = conn->tempsock[i]; @@ -844,7 +858,7 @@ static int domore_getsock(struct connectdata *conn, } /* returns bitmapped flags for this handle and its sockets */ -static int multi_getsock(struct SessionHandle *data, +static int multi_getsock(struct Curl_easy *data, curl_socket_t *socks, /* points to numsocks number of sockets */ int numsocks) @@ -910,15 +924,14 @@ static int multi_getsock(struct SessionHandle *data, } -CURLMcode curl_multi_fdset(CURLM *multi_handle, +CURLMcode curl_multi_fdset(struct Curl_multi *multi, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *exc_fd_set, int *max_fd) { /* Scan through all the easy handles to get the file descriptors set. Some easy handles may not have connected to the remote host yet, and then we must make sure that is done. */ - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct SessionHandle *data; + struct Curl_easy *data; int this_max_fd=-1; curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; int bitmap; @@ -960,14 +973,13 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle, return CURLM_OK; } -CURLMcode curl_multi_wait(CURLM *multi_handle, +CURLMcode curl_multi_wait(struct Curl_multi *multi, struct curl_waitfd extra_fds[], unsigned int extra_nfds, int timeout_ms, int *ret) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct SessionHandle *data; + struct Curl_easy *data; curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE]; int bitmap; unsigned int i; @@ -1130,7 +1142,7 @@ static bool multi_ischanged(struct Curl_multi *multi, bool clear) } CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, - struct SessionHandle *data, + struct Curl_easy *data, struct connectdata *conn) { CURLMcode rc; @@ -1155,7 +1167,7 @@ static CURLcode multi_reconnect_request(struct connectdata **connp) { CURLcode result = CURLE_OK; struct connectdata *conn = *connp; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* This was a re-use of a connection and we got a write error in the * DO-phase. Then we DISCONNECT this connection and have another attempt to @@ -1223,7 +1235,7 @@ static CURLcode multi_do(struct connectdata **connp, bool *done) { CURLcode result=CURLE_OK; struct connectdata *conn = *connp; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(conn->handler->do_it) { /* generic protocol-specific function pointer set in curl_connect() */ @@ -1286,7 +1298,7 @@ static CURLcode multi_do_more(struct connectdata *conn, int *complete) static CURLMcode multi_runsingle(struct Curl_multi *multi, struct timeval now, - struct SessionHandle *data) + struct Curl_easy *data) { struct Curl_message *msg = NULL; bool connected; @@ -1297,14 +1309,18 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, CURLMcode rc; CURLcode result = CURLE_OK; struct SingleRequest *k; - long timeout_ms; + time_t timeout_ms; + time_t recv_timeout_ms; + time_t send_timeout_ms; int control; if(!GOOD_EASY_HANDLE(data)) return CURLM_BAD_EASY_HANDLE; do { - bool disconnect_conn = FALSE; + /* A "stream" here is a logical stream if the protocol can handle that + (HTTP/2), or the full connection for older protocols */ + bool stream_error = FALSE; rc = CURLM_OK; /* Handle the case when the pipe breaks, i.e., the connection @@ -1382,8 +1398,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* Force connection closed if the connection has indeed been used */ if(data->mstate > CURLM_STATE_DO) { - connclose(data->easy_conn, "Disconnected with pending data"); - disconnect_conn = TRUE; + streamclose(data->easy_conn, "Disconnected with pending data"); + stream_error = TRUE; } result = CURLE_OPERATION_TIMEDOUT; (void)multi_done(&data->easy_conn, result, TRUE); @@ -1432,7 +1448,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* Add this handle to the send or pend pipeline */ result = Curl_add_handle_to_pipeline(data, data->easy_conn); if(result) - disconnect_conn = TRUE; + stream_error = TRUE; else { if(async) /* We're now waiting for an asynchronous name lookup */ @@ -1466,8 +1482,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, struct connectdata *conn = data->easy_conn; const char *hostname; - if(conn->bits.proxy) - hostname = conn->proxy.name; + if(conn->bits.httpproxy) + hostname = conn->http_proxy.host.name; else if(conn->bits.conn_to_host) hostname = conn->conn_to_host.name; else @@ -1524,7 +1540,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(result) { /* failure detected */ - disconnect_conn = TRUE; + stream_error = TRUE; break; } } @@ -1543,7 +1559,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, multistate(data, CURLM_STATE_CONNECT); } else if(!result) { - if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_COMPLETE) { + if((data->easy_conn->http_proxy.proxytype != CURLPROXY_HTTPS || + data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) && + (data->easy_conn->tunnel_state[FIRSTSOCKET] != TUNNEL_CONNECT)) { rc = CURLM_CALL_MULTI_PERFORM; /* initiate protocol connect phase */ multistate(data, CURLM_STATE_SENDPROTOCONNECT); @@ -1556,6 +1574,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* awaiting a completion of an asynch TCP connect */ result = Curl_is_connected(data->easy_conn, FIRSTSOCKET, &connected); if(connected && !result) { +#ifndef CURL_DISABLE_HTTP + if((data->easy_conn->http_proxy.proxytype == CURLPROXY_HTTPS && + !data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) || + (data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)) { + multistate(data, CURLM_STATE_WAITPROXYCONNECT); + break; + } +#endif rc = CURLM_CALL_MULTI_PERFORM; multistate(data, data->easy_conn->bits.tunnel_proxy? CURLM_STATE_WAITPROXYCONNECT: @@ -1564,7 +1590,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, else if(result) { /* failure detected */ /* Just break, the cleaning up is handled all in one place */ - disconnect_conn = TRUE; + stream_error = TRUE; break; } break; @@ -1584,7 +1610,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* failure detected */ Curl_posttransfer(data); multi_done(&data->easy_conn, result, TRUE); - disconnect_conn = TRUE; + stream_error = TRUE; } break; @@ -1601,7 +1627,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* failure detected */ Curl_posttransfer(data); multi_done(&data->easy_conn, result, TRUE); - disconnect_conn = TRUE; + stream_error = TRUE; } break; @@ -1676,7 +1702,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(drc) { /* a failure here pretty much implies an out of memory */ result = drc; - disconnect_conn = TRUE; + stream_error = TRUE; } else retry = (newurl)?TRUE:FALSE; @@ -1709,7 +1735,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } else { /* Have error handler disconnect conn if we can't retry */ - disconnect_conn = TRUE; + stream_error = TRUE; free(newurl); } } @@ -1718,7 +1744,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, Curl_posttransfer(data); if(data->easy_conn) multi_done(&data->easy_conn, result, FALSE); - disconnect_conn = TRUE; + stream_error = TRUE; } } break; @@ -1740,7 +1766,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* failure detected */ Curl_posttransfer(data); multi_done(&data->easy_conn, result, FALSE); - disconnect_conn = TRUE; + stream_error = TRUE; } break; @@ -1769,7 +1795,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* failure detected */ Curl_posttransfer(data); multi_done(&data->easy_conn, result, FALSE); - disconnect_conn = TRUE; + stream_error = TRUE; } break; @@ -1805,52 +1831,67 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, else result = Curl_speedcheck(data, now); - if(( (data->set.max_send_speed == 0) || - (data->progress.ulspeed < data->set.max_send_speed)) && - ( (data->set.max_recv_speed == 0) || - (data->progress.dlspeed < data->set.max_recv_speed))) - multistate(data, CURLM_STATE_PERFORM); + if(!result) { + send_timeout_ms = 0; + if(data->set.max_send_speed > 0) + send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded, + data->progress.ul_limit_size, + data->set.max_send_speed, + data->progress.ul_limit_start, + now); + + recv_timeout_ms = 0; + if(data->set.max_recv_speed > 0) + recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded, + data->progress.dl_limit_size, + data->set.max_recv_speed, + data->progress.dl_limit_start, + now); + + if(send_timeout_ms <= 0 && recv_timeout_ms <= 0) + multistate(data, CURLM_STATE_PERFORM); + else if(send_timeout_ms >= recv_timeout_ms) + Curl_expire_latest(data, send_timeout_ms); + else + Curl_expire_latest(data, recv_timeout_ms); + } break; case CURLM_STATE_PERFORM: { char *newurl = NULL; bool retry = FALSE; + bool comeback = FALSE; /* check if over send speed */ - if((data->set.max_send_speed > 0) && - (data->progress.ulspeed > data->set.max_send_speed)) { - int buffersize; - - multistate(data, CURLM_STATE_TOOFAST); - - /* calculate upload rate-limitation timeout. */ - buffersize = (int)(data->set.buffer_size ? - data->set.buffer_size : BUFSIZE); - timeout_ms = Curl_sleep_time(data->set.max_send_speed, - data->progress.ulspeed, buffersize); - Curl_expire_latest(data, timeout_ms); - break; - } + send_timeout_ms = 0; + if(data->set.max_send_speed > 0) + send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded, + data->progress.ul_limit_size, + data->set.max_send_speed, + data->progress.ul_limit_start, + now); /* check if over recv speed */ - if((data->set.max_recv_speed > 0) && - (data->progress.dlspeed > data->set.max_recv_speed)) { - int buffersize; + recv_timeout_ms = 0; + if(data->set.max_recv_speed > 0) + recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded, + data->progress.dl_limit_size, + data->set.max_recv_speed, + data->progress.dl_limit_start, + now); + if(send_timeout_ms > 0 || recv_timeout_ms > 0) { multistate(data, CURLM_STATE_TOOFAST); - - /* Calculate download rate-limitation timeout. */ - buffersize = (int)(data->set.buffer_size ? - data->set.buffer_size : BUFSIZE); - timeout_ms = Curl_sleep_time(data->set.max_recv_speed, - data->progress.dlspeed, buffersize); - Curl_expire_latest(data, timeout_ms); + if(send_timeout_ms >= recv_timeout_ms) + Curl_expire_latest(data, send_timeout_ms); + else + Curl_expire_latest(data, recv_timeout_ms); break; } /* read/write data if it is ready to do so */ - result = Curl_readwrite(data->easy_conn, data, &done); + result = Curl_readwrite(data->easy_conn, data, &done, &comeback); k = &data->req; @@ -1890,10 +1931,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(!(data->easy_conn->handler->flags & PROTOPT_DUAL) && result != CURLE_HTTP2_STREAM) - connclose(data->easy_conn, "Transfer returned error"); + streamclose(data->easy_conn, "Transfer returned error"); Curl_posttransfer(data); - multi_done(&data->easy_conn, result, FALSE); + multi_done(&data->easy_conn, result, TRUE); } else if(done) { followtype follow=FOLLOW_NONE; @@ -1906,7 +1947,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* expire the new receiving pipeline head */ if(data->easy_conn->recv_pipe->head) - Curl_expire_latest(data->easy_conn->recv_pipe->head->ptr, 1); + Curl_expire_latest(data->easy_conn->recv_pipe->head->ptr, 0); /* Check if we can move pending requests to send pipe */ Curl_multi_process_pending_handles(multi); @@ -1949,13 +1990,15 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, if(!result) newurl = NULL; /* allocation was handed over Curl_follow() */ else - disconnect_conn = TRUE; + stream_error = TRUE; } multistate(data, CURLM_STATE_DONE); rc = CURLM_CALL_MULTI_PERFORM; } } + else if(comeback) + rc = CURLM_CALL_MULTI_PERFORM; free(newurl); break; @@ -2014,7 +2057,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, that could be freed anytime */ data->easy_conn = NULL; - Curl_expire(data, 0); /* stop all timers */ + Curl_expire_clear(data); /* stop all timers */ break; case CURLM_STATE_MSGSENT: @@ -2048,7 +2091,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, Curl_removeHandleFromPipeline(data, data->easy_conn->send_pipe); Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe); - if(disconnect_conn) { + if(stream_error) { /* Don't attempt to send data over a connection that timed out */ bool dead_connection = result == CURLE_OPERATION_TIMEDOUT; /* disconnect properly */ @@ -2072,7 +2115,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* aborted due to progress callback return code must close the connection */ result = CURLE_ABORTED_BY_CALLBACK; - connclose(data->easy_conn, "Aborted by callback"); + streamclose(data->easy_conn, "Aborted by callback"); /* if not yet in DONE state, go there, otherwise COMPLETED */ multistate(data, (data->mstate < CURLM_STATE_DONE)? @@ -2102,10 +2145,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, } -CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles) +CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct SessionHandle *data; + struct Curl_easy *data; CURLMcode returncode=CURLM_OK; struct Curl_tree *t; struct timeval now = Curl_tvnow(); @@ -2164,7 +2206,10 @@ static void close_all_connections(struct Curl_multi *multi) conn->data = multi->closure_handle; sigpipe_ignore(conn->data, &pipe_st); + conn->data->easy_conn = NULL; /* clear the easy handle's connection + pointer */ /* This will remove the connection from the cache */ + connclose(conn, "kill all"); (void)Curl_disconnect(conn, FALSE); sigpipe_restore(&pipe_st); @@ -2172,11 +2217,10 @@ static void close_all_connections(struct Curl_multi *multi) } } -CURLMcode curl_multi_cleanup(CURLM *multi_handle) +CURLMcode curl_multi_cleanup(struct Curl_multi *multi) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct SessionHandle *data; - struct SessionHandle *nextdata; + struct Curl_easy *data; + struct Curl_easy *nextdata; if(GOOD_MULTI_HANDLE(multi)) { bool restore_pipe = FALSE; @@ -2247,9 +2291,8 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle) * beyond. The current design is fully O(1). */ -CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue) +CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; struct Curl_message *msg; *msgs_in_queue = 0; /* default to none */ @@ -2280,7 +2323,7 @@ CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue) * call the callback accordingly. */ static void singlesocket(struct Curl_multi *multi, - struct SessionHandle *data) + struct Curl_easy *data) { curl_socket_t socks[MAX_SOCKSPEREASYHANDLE]; int i; @@ -2452,7 +2495,7 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s) /* * add_next_timeout() * - * Each SessionHandle has a list of timeouts. The add_next_timeout() is called + * Each Curl_easy has a list of timeouts. The add_next_timeout() is called * when it has just been removed from the splay tree because the timeout has * expired. This function is then to advance in the list to pick the next * timeout to use (skip the already expired ones) and add this node back to @@ -2463,7 +2506,7 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s) */ static CURLMcode add_next_timeout(struct timeval now, struct Curl_multi *multi, - struct SessionHandle *d) + struct Curl_easy *d) { struct timeval *tv = &d->state.expiretime; struct curl_llist *list = d->state.timeoutlist; @@ -2474,7 +2517,7 @@ static CURLMcode add_next_timeout(struct timeval now, timeout in *tv */ for(e = list->head; e;) { struct curl_llist_element *n = e->next; - long diff = curlx_tvdiff(*(struct timeval *)e->ptr, now); + time_t diff = curlx_tvdiff(*(struct timeval *)e->ptr, now); if(diff <= 0) /* remove outdated entry */ Curl_llist_remove(list, e, NULL); @@ -2511,7 +2554,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, int *running_handles) { CURLMcode result = CURLM_OK; - struct SessionHandle *data = NULL; + struct Curl_easy *data = NULL; struct Curl_tree *t; struct timeval now = Curl_tvnow(); @@ -2639,10 +2682,9 @@ static CURLMcode multi_socket(struct Curl_multi *multi, } #undef curl_multi_setopt -CURLMcode curl_multi_setopt(CURLM *multi_handle, +CURLMcode curl_multi_setopt(struct Curl_multi *multi, CURLMoption option, ...) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; CURLMcode res = CURLM_OK; va_list param; @@ -2710,33 +2752,32 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle, /* we define curl_multi_socket() in the public multi.h header */ #undef curl_multi_socket -CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, +CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s, int *running_handles) { - CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s, - 0, running_handles); + CURLMcode result = multi_socket(multi, FALSE, s, 0, running_handles); if(CURLM_OK >= result) - update_timer((struct Curl_multi *)multi_handle); + update_timer(multi); return result; } -CURLMcode curl_multi_socket_action(CURLM *multi_handle, curl_socket_t s, +CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s, int ev_bitmask, int *running_handles) { - CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s, + CURLMcode result = multi_socket(multi, FALSE, s, ev_bitmask, running_handles); if(CURLM_OK >= result) - update_timer((struct Curl_multi *)multi_handle); + update_timer(multi); return result; } -CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles) +CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles) { - CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, - TRUE, CURL_SOCKET_BAD, 0, running_handles); + CURLMcode result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, + running_handles); if(CURLM_OK >= result) - update_timer((struct Curl_multi *)multi_handle); + update_timer(multi); return result; } @@ -2754,7 +2795,7 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) { /* some time left before expiration */ - *timeout_ms = curlx_tvdiff(multi->timetree->key, now); + *timeout_ms = (long)curlx_tvdiff(multi->timetree->key, now); if(!*timeout_ms) /* * Since we only provide millisecond resolution on the returned value @@ -2775,11 +2816,9 @@ static CURLMcode multi_timeout(struct Curl_multi *multi, return CURLM_OK; } -CURLMcode curl_multi_timeout(CURLM *multi_handle, +CURLMcode curl_multi_timeout(struct Curl_multi *multi, long *timeout_ms) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; @@ -2806,7 +2845,7 @@ static int update_timer(struct Curl_multi *multi) multi->timer_lastcall = none; /* there's no timeout now but there was one previously, tell the app to disable it */ - return multi->timer_cb((CURLM*)multi, -1, multi->timer_userp); + return multi->timer_cb(multi, -1, multi->timer_userp); } return 0; } @@ -2820,7 +2859,7 @@ static int update_timer(struct Curl_multi *multi) multi->timer_lastcall = multi->timetree->key; - return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp); + return multi->timer_cb(multi, timeout_ms, multi->timer_userp); } /* @@ -2863,7 +2902,7 @@ multi_addtimeout(struct curl_llist *timeoutlist, /* find the correct spot in the list */ for(e = timeoutlist->head; e; e = e->next) { struct timeval *checktime = e->ptr; - long diff = curlx_tvdiff(*checktime, *timedup); + time_t diff = curlx_tvdiff(*checktime, *timedup); if(diff > 0) break; prev = e; @@ -2887,92 +2926,59 @@ multi_addtimeout(struct curl_llist *timeoutlist, * given a number of milliseconds from now to use to set the 'act before * this'-time for the transfer, to be extracted by curl_multi_timeout() * - * Note that the timeout will be added to a queue of timeouts if it defines a - * moment in time that is later than the current head of queue. - * - * Pass zero to clear all timeout values for this handle. -*/ -void Curl_expire(struct SessionHandle *data, long milli) + * The timeout will be added to a queue of timeouts if it defines a moment in + * time that is later than the current head of queue. + */ +void Curl_expire(struct Curl_easy *data, time_t milli) { struct Curl_multi *multi = data->multi; struct timeval *nowp = &data->state.expiretime; int rc; + struct timeval set; /* this is only interesting while there is still an associated multi struct remaining! */ if(!multi) return; - if(!milli) { - /* No timeout, clear the time data. */ - if(nowp->tv_sec || nowp->tv_usec) { - /* Since this is an cleared time, we must remove the previous entry from - the splay tree */ - struct curl_llist *list = data->state.timeoutlist; + set = Curl_tvnow(); + set.tv_sec += (long)(milli/1000); + set.tv_usec += (milli%1000)*1000; - rc = Curl_splayremovebyaddr(multi->timetree, - &data->state.timenode, - &multi->timetree); - if(rc) - infof(data, "Internal error clearing splay node = %d\n", rc); - - /* flush the timeout list too */ - while(list->size > 0) - Curl_llist_remove(list, list->tail, NULL); - -#ifdef DEBUGBUILD - infof(data, "Expire cleared\n"); -#endif - nowp->tv_sec = 0; - nowp->tv_usec = 0; - } + if(set.tv_usec >= 1000000) { + set.tv_sec++; + set.tv_usec -= 1000000; } - else { - struct timeval set; - set = Curl_tvnow(); - set.tv_sec += milli/1000; - set.tv_usec += (milli%1000)*1000; - - if(set.tv_usec >= 1000000) { - set.tv_sec++; - set.tv_usec -= 1000000; + if(nowp->tv_sec || nowp->tv_usec) { + /* This means that the struct is added as a node in the splay tree. + Compare if the new time is earlier, and only remove-old/add-new if it + is. */ + time_t diff = curlx_tvdiff(set, *nowp); + if(diff > 0) { + /* the new expire time was later so just add it to the queue + and get out */ + multi_addtimeout(data->state.timeoutlist, &set); + return; } - if(nowp->tv_sec || nowp->tv_usec) { - /* This means that the struct is added as a node in the splay tree. - Compare if the new time is earlier, and only remove-old/add-new if it - is. */ - long diff = curlx_tvdiff(set, *nowp); - if(diff > 0) { - /* the new expire time was later so just add it to the queue - and get out */ - multi_addtimeout(data->state.timeoutlist, &set); - return; - } + /* the new time is newer than the presently set one, so add the current + to the queue and update the head */ + multi_addtimeout(data->state.timeoutlist, nowp); - /* the new time is newer than the presently set one, so add the current - to the queue and update the head */ - multi_addtimeout(data->state.timeoutlist, nowp); - - /* Since this is an updated time, we must remove the previous entry from - the splay tree first and then re-add the new value */ - rc = Curl_splayremovebyaddr(multi->timetree, - &data->state.timenode, - &multi->timetree); - if(rc) - infof(data, "Internal error removing splay node = %d\n", rc); - } - - *nowp = set; - data->state.timenode.payload = data; - multi->timetree = Curl_splayinsert(*nowp, - multi->timetree, - &data->state.timenode); + /* Since this is an updated time, we must remove the previous entry from + the splay tree first and then re-add the new value */ + rc = Curl_splayremovebyaddr(multi->timetree, + &data->state.timenode, + &multi->timetree); + if(rc) + infof(data, "Internal error removing splay node = %d\n", rc); } -#if 0 - Curl_splayprint(multi->timetree, 0, TRUE); -#endif + + *nowp = set; + data->state.timenode.payload = data; + multi->timetree = Curl_splayinsert(*nowp, multi->timetree, + &data->state.timenode); } /* @@ -2986,14 +2992,14 @@ void Curl_expire(struct SessionHandle *data, long milli) * time-out period to expire. * */ -void Curl_expire_latest(struct SessionHandle *data, long milli) +void Curl_expire_latest(struct Curl_easy *data, time_t milli) { struct timeval *expire = &data->state.expiretime; struct timeval set; set = Curl_tvnow(); - set.tv_sec += milli / 1000; + set.tv_sec += (long)(milli / 1000); set.tv_usec += (milli % 1000) * 1000; if(set.tv_usec >= 1000000) { @@ -3005,7 +3011,7 @@ void Curl_expire_latest(struct SessionHandle *data, long milli) /* This means that the struct is added as a node in the splay tree. Compare if the new time is earlier, and only remove-old/add-new if it is. */ - long diff = curlx_tvdiff(set, *expire); + time_t diff = curlx_tvdiff(set, *expire); if(diff > 0) /* the new expire time was later than the top time, so just skip this */ return; @@ -3015,11 +3021,53 @@ void Curl_expire_latest(struct SessionHandle *data, long milli) Curl_expire(data, milli); } -CURLMcode curl_multi_assign(CURLM *multi_handle, - curl_socket_t s, void *hashp) + +/* + * Curl_expire_clear() + * + * Clear ALL timeout values for this handle. + */ +void Curl_expire_clear(struct Curl_easy *data) +{ + struct Curl_multi *multi = data->multi; + struct timeval *nowp = &data->state.expiretime; + int rc; + + /* this is only interesting while there is still an associated multi struct + remaining! */ + if(!multi) + return; + + if(nowp->tv_sec || nowp->tv_usec) { + /* Since this is an cleared time, we must remove the previous entry from + the splay tree */ + struct curl_llist *list = data->state.timeoutlist; + + rc = Curl_splayremovebyaddr(multi->timetree, + &data->state.timenode, + &multi->timetree); + if(rc) + infof(data, "Internal error clearing splay node = %d\n", rc); + + /* flush the timeout list too */ + while(list->size > 0) + Curl_llist_remove(list, list->tail, NULL); + +#ifdef DEBUGBUILD + infof(data, "Expire cleared\n"); +#endif + nowp->tv_sec = 0; + nowp->tv_usec = 0; + } +} + + + + +CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s, + void *hashp) { struct Curl_sh_entry *there = NULL; - struct Curl_multi *multi = (struct Curl_multi *)multi_handle; there = sh_getentry(&multi->sockhash, s); @@ -3066,7 +3114,7 @@ void Curl_multi_process_pending_handles(struct Curl_multi *multi) struct curl_llist_element *e = multi->pending->head; while(e) { - struct SessionHandle *data = e->ptr; + struct Curl_easy *data = e->ptr; struct curl_llist_element *next = e->next; if(data->mstate == CURLM_STATE_CONNECT_PEND) { @@ -3076,7 +3124,7 @@ void Curl_multi_process_pending_handles(struct Curl_multi *multi) Curl_llist_remove(multi->pending, e, NULL); /* Make sure that the handle will be processed soonish. */ - Curl_expire_latest(data, 1); + Curl_expire_latest(data, 0); } e = next; /* operate on next handle */ @@ -3084,10 +3132,9 @@ void Curl_multi_process_pending_handles(struct Curl_multi *multi) } #ifdef DEBUGBUILD -void Curl_multi_dump(const struct Curl_multi *multi_handle) +void Curl_multi_dump(struct Curl_multi *multi) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; - struct SessionHandle *data; + struct Curl_easy *data; int i; fprintf(stderr, "* Multi status: %d handles, %d alive\n", multi->num_easy, multi->num_alive); diff --git a/contrib/curl/lib/multihandle.h b/contrib/curl/lib/multihandle.h index fc81a554..0b78de94 100644 --- a/contrib/curl/lib/multihandle.h +++ b/contrib/curl/lib/multihandle.h @@ -38,7 +38,9 @@ typedef enum { CURLM_STATE_CONNECT, /* 2 - resolve/connect has been sent off */ CURLM_STATE_WAITRESOLVE, /* 3 - awaiting the resolve to finalize */ CURLM_STATE_WAITCONNECT, /* 4 - awaiting the TCP connect to finalize */ - CURLM_STATE_WAITPROXYCONNECT, /* 5 - awaiting proxy CONNECT to finalize */ + CURLM_STATE_WAITPROXYCONNECT, /* 5 - awaiting HTTPS proxy SSL initialization + to complete and/or proxy CONNECT to + finalize */ CURLM_STATE_SENDPROTOCONNECT, /* 6 - initiate protocol connect procedure */ CURLM_STATE_PROTOCONNECT, /* 7 - completing the protocol-specific connect phase */ @@ -71,8 +73,8 @@ struct Curl_multi { long type; /* We have a doubly-linked circular list with easy handles */ - struct SessionHandle *easyp; - struct SessionHandle *easylp; /* last node */ + struct Curl_easy *easyp; + struct Curl_easy *easylp; /* last node */ int num_easy; /* amount of entries in the linked list above. */ int num_alive; /* amount of easy handles that are added but have not yet @@ -80,7 +82,7 @@ struct Curl_multi { struct curl_llist *msglist; /* a list of messages from completed transfers */ - struct curl_llist *pending; /* SessionHandles that are in the + struct curl_llist *pending; /* Curl_easys that are in the CURLM_STATE_CONNECT_PEND state */ /* callback function and user data pointer for the *socket() API */ @@ -113,7 +115,7 @@ struct Curl_multi { /* This handle will be used for closing the cached connections in curl_multi_cleanup() */ - struct SessionHandle *closure_handle; + struct Curl_easy *closure_handle; long maxconnects; /* if >0, a fixed limit of the maximum number of entries we're allowed to grow the connection cache to */ diff --git a/contrib/curl/lib/multiif.h b/contrib/curl/lib/multiif.h index b229f53e..e5de1fc4 100644 --- a/contrib/curl/lib/multiif.h +++ b/contrib/curl/lib/multiif.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -25,10 +25,11 @@ /* * Prototypes for library-wide functions provided by multi.c */ -void Curl_expire(struct SessionHandle *data, long milli); -void Curl_expire_latest(struct SessionHandle *data, long milli); +void Curl_expire(struct Curl_easy *data, time_t milli); +void Curl_expire_clear(struct Curl_easy *data); +void Curl_expire_latest(struct Curl_easy *data, time_t milli); bool Curl_pipeline_wanted(const struct Curl_multi* multi, int bits); -void Curl_multi_handlePipeBreak(struct SessionHandle *data); +void Curl_multi_handlePipeBreak(struct Curl_easy *data); /* Internal version of curl_multi_init() accepts size parameters for the socket and connection hashes */ @@ -51,7 +52,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize); * allow easier tracking of the internal handle's state and what sockets * they use. Only for research and development DEBUGBUILD enabled builds. */ -void Curl_multi_dump(const struct Curl_multi *multi_handle); +void Curl_multi_dump(struct Curl_multi *multi); #endif void Curl_multi_process_pending_handles(struct Curl_multi *multi); @@ -92,6 +93,6 @@ void Curl_multi_closed(struct connectdata *conn, curl_socket_t s); * Add a handle and move it into PERFORM state at once. For pushed streams. */ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, - struct SessionHandle *data, + struct Curl_easy *data, struct connectdata *conn); #endif /* HEADER_CURL_MULTIIF_H */ diff --git a/contrib/curl/lib/netrc.c b/contrib/curl/lib/netrc.c index 46f427a2..996711d1 100644 --- a/contrib/curl/lib/netrc.c +++ b/contrib/curl/lib/netrc.c @@ -28,10 +28,8 @@ #include #include "netrc.h" - -#include "strequal.h" #include "strtok.h" -#include "rawstr.h" +#include "strcase.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -130,20 +128,20 @@ int Curl_parsenetrc(const char *host, switch(state) { case NOTHING: - if(Curl_raw_equal("machine", tok)) { + if(strcasecompare("machine", tok)) { /* the next tok is the machine name, this is in itself the delimiter that starts the stuff entered for this machine, after this we need to search for 'login' and 'password'. */ state=HOSTFOUND; } - else if(Curl_raw_equal("default", tok)) { + else if(strcasecompare("default", tok)) { state=HOSTVALID; retcode=0; /* we did find our host */ } break; case HOSTFOUND: - if(Curl_raw_equal(host, tok)) { + if(strcasecompare(host, tok)) { /* and yes, this is our host! */ state=HOSTVALID; retcode=0; /* we did find our host */ @@ -156,7 +154,7 @@ int Curl_parsenetrc(const char *host, /* we are now parsing sub-keywords concerning "our" host */ if(state_login) { if(specific_login) { - state_our_login = Curl_raw_equal(*loginp, tok); + state_our_login = strcasecompare(*loginp, tok); } else { free(*loginp); @@ -179,11 +177,11 @@ int Curl_parsenetrc(const char *host, } state_password=0; } - else if(Curl_raw_equal("login", tok)) + else if(strcasecompare("login", tok)) state_login=1; - else if(Curl_raw_equal("password", tok)) + else if(strcasecompare("password", tok)) state_password=1; - else if(Curl_raw_equal("machine", tok)) { + else if(strcasecompare("machine", tok)) { /* ok, there's machine here go => */ state = HOSTFOUND; state_our_login = FALSE; diff --git a/contrib/curl/lib/non-ascii.c b/contrib/curl/lib/non-ascii.c index 205ff04b..2f5de4c6 100644 --- a/contrib/curl/lib/non-ascii.c +++ b/contrib/curl/lib/non-ascii.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -51,7 +51,7 @@ * Curl_convert_clone() returns a malloced copy of the source string (if * returning CURLE_OK), with the data converted to network format. */ -CURLcode Curl_convert_clone(struct SessionHandle *data, +CURLcode Curl_convert_clone(struct Curl_easy *data, const char *indata, size_t insize, char **outbuf) @@ -79,7 +79,7 @@ CURLcode Curl_convert_clone(struct SessionHandle *data, * Curl_convert_to_network() is an internal function for performing ASCII * conversions on non-ASCII platforms. It convers the buffer _in place_. */ -CURLcode Curl_convert_to_network(struct SessionHandle *data, +CURLcode Curl_convert_to_network(struct Curl_easy *data, char *buffer, size_t length) { if(data->set.convtonetwork) { @@ -117,7 +117,7 @@ CURLcode Curl_convert_to_network(struct SessionHandle *data, /* call iconv */ input_ptr = output_ptr = buffer; in_bytes = out_bytes = length; - rc = iconv(data->outbound_cd, (const char**)&input_ptr, &in_bytes, + rc = iconv(data->outbound_cd, (const char **)&input_ptr, &in_bytes, &output_ptr, &out_bytes); if((rc == ICONV_ERROR) || (in_bytes != 0)) { error = ERRNO; @@ -139,7 +139,7 @@ CURLcode Curl_convert_to_network(struct SessionHandle *data, * Curl_convert_from_network() is an internal function for performing ASCII * conversions on non-ASCII platforms. It convers the buffer _in place_. */ -CURLcode Curl_convert_from_network(struct SessionHandle *data, +CURLcode Curl_convert_from_network(struct Curl_easy *data, char *buffer, size_t length) { if(data->set.convfromnetwork) { @@ -199,7 +199,7 @@ CURLcode Curl_convert_from_network(struct SessionHandle *data, * Curl_convert_from_utf8() is an internal function for performing UTF-8 * conversions on non-ASCII platforms. */ -CURLcode Curl_convert_from_utf8(struct SessionHandle *data, +CURLcode Curl_convert_from_utf8(struct Curl_easy *data, char *buffer, size_t length) { if(data->set.convfromutf8) { @@ -261,9 +261,9 @@ CURLcode Curl_convert_from_utf8(struct SessionHandle *data, } /* - * Init conversion stuff for a SessionHandle + * Init conversion stuff for a Curl_easy */ -void Curl_convert_init(struct SessionHandle *data) +void Curl_convert_init(struct Curl_easy *data) { #if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) /* conversion descriptors for iconv calls */ @@ -276,9 +276,9 @@ void Curl_convert_init(struct SessionHandle *data) } /* - * Setup conversion stuff for a SessionHandle + * Setup conversion stuff for a Curl_easy */ -void Curl_convert_setup(struct SessionHandle *data) +void Curl_convert_setup(struct Curl_easy *data) { data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, CURL_ICONV_CODESET_OF_NETWORK); @@ -289,10 +289,10 @@ void Curl_convert_setup(struct SessionHandle *data) } /* - * Close conversion stuff for a SessionHandle + * Close conversion stuff for a Curl_easy */ -void Curl_convert_close(struct SessionHandle *data) +void Curl_convert_close(struct Curl_easy *data) { #ifdef HAVE_ICONV /* close iconv conversion descriptors */ @@ -314,7 +314,7 @@ void Curl_convert_close(struct SessionHandle *data) * Curl_convert_form() is used from http.c, this converts any form items that need to be sent in the network encoding. Returns CURLE_OK on success. */ -CURLcode Curl_convert_form(struct SessionHandle *data, struct FormData *form) +CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form) { CURLcode result; diff --git a/contrib/curl/lib/non-ascii.h b/contrib/curl/lib/non-ascii.h index f3e2049e..e27f1f41 100644 --- a/contrib/curl/lib/non-ascii.h +++ b/contrib/curl/lib/non-ascii.h @@ -33,22 +33,22 @@ * * If no conversion was needed *outbuf may be NULL. */ -CURLcode Curl_convert_clone(struct SessionHandle *data, +CURLcode Curl_convert_clone(struct Curl_easy *data, const char *indata, size_t insize, char **outbuf); -void Curl_convert_init(struct SessionHandle *data); -void Curl_convert_setup(struct SessionHandle *data); -void Curl_convert_close(struct SessionHandle *data); +void Curl_convert_init(struct Curl_easy *data); +void Curl_convert_setup(struct Curl_easy *data); +void Curl_convert_close(struct Curl_easy *data); -CURLcode Curl_convert_to_network(struct SessionHandle *data, +CURLcode Curl_convert_to_network(struct Curl_easy *data, char *buffer, size_t length); -CURLcode Curl_convert_from_network(struct SessionHandle *data, +CURLcode Curl_convert_from_network(struct Curl_easy *data, char *buffer, size_t length); -CURLcode Curl_convert_from_utf8(struct SessionHandle *data, +CURLcode Curl_convert_from_utf8(struct Curl_easy *data, char *buffer, size_t length); -CURLcode Curl_convert_form(struct SessionHandle *data, struct FormData *form); +CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form); #else #define Curl_convert_clone(a,b,c,d) ((void)a, CURLE_OK) #define Curl_convert_init(x) Curl_nop_stmt diff --git a/contrib/curl/lib/nwlib.c b/contrib/curl/lib/nwlib.c index 42b6aa0d..290cbe31 100644 --- a/contrib/curl/lib/nwlib.c +++ b/contrib/curl/lib/nwlib.c @@ -184,7 +184,8 @@ int GetOrSetUpData(int id, libdata_t **appData, */ NXLock(gLibLock); - if(!(app_data = (libdata_t *) get_app_data(id))) { + app_data = (libdata_t *) get_app_data(id); + if(!app_data) { app_data = malloc(sizeof(libdata_t)); if(app_data) { @@ -259,7 +260,8 @@ int GetOrSetUpData(int id, libdata_t **appData, err = ENOMEM; } - if((err = NXKeySetValue(key, thread_data))) { + err = NXKeySetValue(key, thread_data); + if(err) { free(thread_data->twentybytes); free(thread_data); thread_data = (libthreaddata_t *) NULL; @@ -303,14 +305,14 @@ void DisposeThreadData(void *data) /* For native CLib-based NLM seems we can do a bit more simple. */ #include -int main (void) +int main(void) { /* initialize any globals here... */ /* do this if any global initializing was done SynchronizeStart(); */ - ExitThread (TSR_THREAD, 0); + ExitThread(TSR_THREAD, 0); return 0; } diff --git a/contrib/curl/lib/nwos.c b/contrib/curl/lib/nwos.c index 385f9c8a..c6c22ccb 100644 --- a/contrib/curl/lib/nwos.c +++ b/contrib/curl/lib/nwos.c @@ -26,7 +26,7 @@ #ifdef __NOVELL_LIBC__ /* For native LibC-based NLM we need to do nothing. */ -int netware_init (void) +int netware_init(void) { return 0; } @@ -45,7 +45,7 @@ NETDB_DEFINE_CONTEXT #include NETINET_DEFINE_CONTEXT -int netware_init (void) +int netware_init(void) { int rc = 0; unsigned int myHandle = GetNLMHandle(); @@ -72,13 +72,13 @@ int netware_init (void) } /* dummy function to satisfy newer prelude */ -int __init_environment (void) +int __init_environment(void) { return 0; } /* dummy function to satisfy newer prelude */ -int __deinit_environment (void) +int __deinit_environment(void) { return 0; } diff --git a/contrib/curl/lib/openldap.c b/contrib/curl/lib/openldap.c index 01567acd..4b8cfb9c 100644 --- a/contrib/curl/lib/openldap.c +++ b/contrib/curl/lib/openldap.c @@ -150,7 +150,7 @@ static CURLcode ldap_setup_connection(struct connectdata *conn) { ldapconninfo *li; LDAPURLDesc *lud; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; int rc, proto; CURLcode status; @@ -188,7 +188,7 @@ static Sockbuf_IO ldapsb_tls; static CURLcode ldap_connect(struct connectdata *conn, bool *done) { ldapconninfo *li = conn->proto.generic; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int rc, proto = LDAP_VERSION3; char hosturl[1024]; char *ptr; @@ -226,7 +226,7 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done) static CURLcode ldap_connecting(struct connectdata *conn, bool *done) { ldapconninfo *li = conn->proto.generic; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; LDAPMessage *msg = NULL; struct timeval tv = {0, 1}, *tvp; int rc, err; @@ -352,7 +352,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done) int rc = 0; LDAPURLDesc *ludp = NULL; int msgid; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; connkeep(conn, "OpenLDAP do"); @@ -415,7 +415,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err) { ldapconninfo *li = conn->proto.generic; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; ldapreqinfo *lr = data->req.protop; int rc, ret; LDAPMessage *msg = NULL; diff --git a/contrib/curl/lib/parsedate.c b/contrib/curl/lib/parsedate.c index dfcf855c..3c783be4 100644 --- a/contrib/curl/lib/parsedate.c +++ b/contrib/curl/lib/parsedate.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -80,7 +80,7 @@ #endif #include -#include "rawstr.h" +#include "strcase.h" #include "warnless.h" #include "parsedate.h" @@ -211,7 +211,7 @@ static int checkday(const char *check, size_t len) else what = &Curl_wkday[0]; for(i=0; i<7; i++) { - if(Curl_raw_equal(check, what[0])) { + if(strcasecompare(check, what[0])) { found=TRUE; break; } @@ -228,7 +228,7 @@ static int checkmonth(const char *check) what = &Curl_month[0]; for(i=0; i<12; i++) { - if(Curl_raw_equal(check, what[0])) { + if(strcasecompare(check, what[0])) { found=TRUE; break; } @@ -248,7 +248,7 @@ static int checktz(const char *check) what = tz; for(i=0; i< sizeof(tz)/sizeof(tz[0]); i++) { - if(Curl_raw_equal(check, what->name)) { + if(strcasecompare(check, what->name)) { found=TRUE; break; } @@ -386,15 +386,17 @@ static int parsedate(const char *date, time_t *output) /* a digit */ int val; char *end; + int len=0; if((secnum == -1) && - (3 == sscanf(date, "%02d:%02d:%02d", &hournum, &minnum, &secnum))) { + (3 == sscanf(date, "%02d:%02d:%02d%n", + &hournum, &minnum, &secnum, &len))) { /* time stamp! */ - date += 8; + date += len; } else if((secnum == -1) && - (2 == sscanf(date, "%02d:%02d", &hournum, &minnum))) { + (2 == sscanf(date, "%02d:%02d%n", &hournum, &minnum, &len))) { /* time stamp without seconds */ - date += 5; + date += len; secnum = 0; } else { diff --git a/contrib/curl/lib/pingpong.c b/contrib/curl/lib/pingpong.c index ce2b5861..7a993572 100644 --- a/contrib/curl/lib/pingpong.c +++ b/contrib/curl/lib/pingpong.c @@ -44,12 +44,12 @@ /* Returns timeout in ms. 0 or negative number means the timeout has already triggered */ -long Curl_pp_state_timeout(struct pingpong *pp) +time_t Curl_pp_state_timeout(struct pingpong *pp) { struct connectdata *conn = pp->conn; - struct SessionHandle *data=conn->data; - long timeout_ms; /* in milliseconds */ - long timeout2_ms; /* in milliseconds */ + struct Curl_easy *data=conn->data; + time_t timeout_ms; /* in milliseconds */ + time_t timeout2_ms; /* in milliseconds */ long response_time= (data->set.server_response_timeout)? data->set.server_response_timeout: pp->response_time; @@ -83,9 +83,9 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block) struct connectdata *conn = pp->conn; curl_socket_t sock = conn->sock[FIRSTSOCKET]; int rc; - long interval_ms; - long timeout_ms = Curl_pp_state_timeout(pp); - struct SessionHandle *data=conn->data; + time_t interval_ms; + time_t timeout_ms = Curl_pp_state_timeout(pp); + struct Curl_easy *data=conn->data; CURLcode result = CURLE_OK; if(timeout_ms <=0) { @@ -101,14 +101,17 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block) else interval_ms = 0; /* immediate */ - if(Curl_pp_moredata(pp)) + if(Curl_ssl_data_pending(conn, FIRSTSOCKET)) + rc = 1; + else if(Curl_pp_moredata(pp)) /* We are receiving and there is data in the cache so just read it */ rc = 1; else if(!pp->sendleft && Curl_ssl_data_pending(conn, FIRSTSOCKET)) /* We are receiving and there is data ready in the SSL library */ rc = 1; else - rc = Curl_socket_ready(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */ + rc = Curl_socket_check(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */ + CURL_SOCKET_BAD, pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */ interval_ms); @@ -165,7 +168,7 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp, char *s; CURLcode result; struct connectdata *conn = pp->conn; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; #ifdef HAVE_GSSAPI enum protection_level data_sec = conn->data_prot; @@ -271,7 +274,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd, ssize_t gotbytes; char *ptr; struct connectdata *conn = pp->conn; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char * const buf = data->state.buffer; CURLcode result = CURLE_OK; diff --git a/contrib/curl/lib/pingpong.h b/contrib/curl/lib/pingpong.h index 2f649d5b..500100ae 100644 --- a/contrib/curl/lib/pingpong.h +++ b/contrib/curl/lib/pingpong.h @@ -88,7 +88,7 @@ void Curl_pp_init(struct pingpong *pp); /* Returns timeout in ms. 0 or negative number means the timeout has already triggered */ -long Curl_pp_state_timeout(struct pingpong *pp); +time_t Curl_pp_state_timeout(struct pingpong *pp); /*********************************************************************** diff --git a/contrib/curl/lib/pipeline.c b/contrib/curl/lib/pipeline.c index 95b89b54..40a5e82d 100644 --- a/contrib/curl/lib/pipeline.c +++ b/contrib/curl/lib/pipeline.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2013, Linus Nielsen Feltzing, - * Copyright (C) 2013-2015, Daniel Stenberg, , et al. + * Copyright (C) 2013-2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -31,7 +31,7 @@ #include "multiif.h" #include "pipeline.h" #include "sendf.h" -#include "rawstr.h" +#include "strcase.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -57,7 +57,7 @@ static void server_blacklist_llist_dtor(void *user, void *element) free(element); } -bool Curl_pipeline_penalized(struct SessionHandle *data, +bool Curl_pipeline_penalized(struct Curl_easy *data, struct connectdata *conn) { if(data) { @@ -70,7 +70,7 @@ bool Curl_pipeline_penalized(struct SessionHandle *data, /* Find the head of the recv pipe, if any */ if(conn->recv_pipe && conn->recv_pipe->head) { - struct SessionHandle *recv_handle = conn->recv_pipe->head->ptr; + struct Curl_easy *recv_handle = conn->recv_pipe->head->ptr; recv_size = recv_handle->req.size; @@ -91,7 +91,7 @@ bool Curl_pipeline_penalized(struct SessionHandle *data, return FALSE; } -static CURLcode addHandleToPipeline(struct SessionHandle *data, +static CURLcode addHandleToPipeline(struct Curl_easy *data, struct curl_llist *pipeline) { if(!Curl_llist_insert_next(pipeline, pipeline->tail, data)) @@ -100,7 +100,7 @@ static CURLcode addHandleToPipeline(struct SessionHandle *data, } -CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle, +CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle, struct connectdata *conn) { struct curl_llist_element *sendhead = conn->send_pipe->head; @@ -114,7 +114,7 @@ CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle, if(pipeline == conn->send_pipe && sendhead != conn->send_pipe->head) { /* this is a new one as head, expire it */ Curl_pipeline_leave_write(conn); /* not in use yet */ - Curl_expire(conn->send_pipe->head->ptr, 1); + Curl_expire(conn->send_pipe->head->ptr, 0); } #if 0 /* enable for pipeline debugging */ @@ -130,7 +130,7 @@ CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle, checked to update what sockets it acts on. */ -void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle, +void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle, struct connectdata *conn) { struct curl_llist_element *curr; @@ -149,7 +149,7 @@ void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle, infof(conn->data, "%p is at send pipe head B!\n", (void *)conn->send_pipe->head->ptr); #endif - Curl_expire(conn->send_pipe->head->ptr, 1); + Curl_expire(conn->send_pipe->head->ptr, 0); } /* The receiver's list is not really interesting here since either this @@ -162,7 +162,7 @@ void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle, } } -bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle, +bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle, struct connectdata *conn) { if(handle->multi) { @@ -177,7 +177,7 @@ bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle, struct site_blacklist_entry *site; site = curr->ptr; - if(Curl_raw_equal(site->hostname, conn->host.name) && + if(strcasecompare(site->hostname, conn->host.name) && site->port == conn->remote_port) { infof(handle, "Site %s:%d is pipeline blacklisted\n", conn->host.name, conn->remote_port); @@ -254,7 +254,7 @@ CURLMcode Curl_pipeline_set_site_blacklist(char **sites, return CURLM_OK; } -bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle, +bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle, char *server_name) { if(handle->multi && server_name) { @@ -269,7 +269,7 @@ bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle, char *bl_server_name; bl_server_name = curr->ptr; - if(Curl_raw_nequal(bl_server_name, server_name, + if(strncasecompare(bl_server_name, server_name, strlen(bl_server_name))) { infof(handle, "Server %s is blacklisted\n", server_name); return TRUE; @@ -299,11 +299,16 @@ CURLMcode Curl_pipeline_set_server_blacklist(char **servers, char *server_name; server_name = strdup(*servers); - if(!server_name) + if(!server_name) { + Curl_llist_destroy(new_list, NULL); return CURLM_OUT_OF_MEMORY; + } - if(!Curl_llist_insert_next(new_list, new_list->tail, server_name)) + if(!Curl_llist_insert_next(new_list, new_list->tail, server_name)) { + Curl_llist_destroy(new_list, NULL); + Curl_safefree(server_name); return CURLM_OUT_OF_MEMORY; + } servers++; } @@ -320,7 +325,7 @@ CURLMcode Curl_pipeline_set_server_blacklist(char **servers, return CURLM_OK; } -static bool pipe_head(struct SessionHandle *data, +static bool pipe_head(struct Curl_easy *data, struct curl_llist *pipeline) { if(pipeline) { @@ -332,14 +337,14 @@ static bool pipe_head(struct SessionHandle *data, } /* returns TRUE if the given handle is head of the recv pipe */ -bool Curl_recvpipe_head(struct SessionHandle *data, +bool Curl_recvpipe_head(struct Curl_easy *data, struct connectdata *conn) { return pipe_head(data, conn->recv_pipe); } /* returns TRUE if the given handle is head of the send pipe */ -bool Curl_sendpipe_head(struct SessionHandle *data, +bool Curl_sendpipe_head(struct Curl_easy *data, struct connectdata *conn) { return pipe_head(data, conn->send_pipe); @@ -353,7 +358,7 @@ bool Curl_sendpipe_head(struct SessionHandle *data, * If not available, return FALSE. */ -bool Curl_pipeline_checkget_write(struct SessionHandle *data, +bool Curl_pipeline_checkget_write(struct Curl_easy *data, struct connectdata *conn) { if(conn->bits.multiplex) @@ -376,7 +381,7 @@ bool Curl_pipeline_checkget_write(struct SessionHandle *data, * If not available, return FALSE. */ -bool Curl_pipeline_checkget_read(struct SessionHandle *data, +bool Curl_pipeline_checkget_read(struct Curl_easy *data, struct connectdata *conn) { if(conn->bits.multiplex) @@ -413,7 +418,7 @@ void print_pipeline(struct connectdata *conn) { struct curl_llist_element *curr; struct connectbundle *cb_ptr; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; cb_ptr = conn->bundle; diff --git a/contrib/curl/lib/pipeline.h b/contrib/curl/lib/pipeline.h index a39dfa8d..a64f7102 100644 --- a/contrib/curl/lib/pipeline.h +++ b/contrib/curl/lib/pipeline.h @@ -23,34 +23,34 @@ * ***************************************************************************/ -CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle, +CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle, struct connectdata *conn); -void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle, +void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle, struct connectdata *conn); -bool Curl_pipeline_penalized(struct SessionHandle *data, +bool Curl_pipeline_penalized(struct Curl_easy *data, struct connectdata *conn); -bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle, +bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle, struct connectdata *conn); CURLMcode Curl_pipeline_set_site_blacklist(char **sites, struct curl_llist **list_ptr); -bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle, +bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle, char *server_name); CURLMcode Curl_pipeline_set_server_blacklist(char **servers, struct curl_llist **list_ptr); -bool Curl_pipeline_checkget_write(struct SessionHandle *data, +bool Curl_pipeline_checkget_write(struct Curl_easy *data, struct connectdata *conn); -bool Curl_pipeline_checkget_read(struct SessionHandle *data, +bool Curl_pipeline_checkget_read(struct Curl_easy *data, struct connectdata *conn); void Curl_pipeline_leave_write(struct connectdata *conn); void Curl_pipeline_leave_read(struct connectdata *conn); -bool Curl_recvpipe_head(struct SessionHandle *data, +bool Curl_recvpipe_head(struct Curl_easy *data, struct connectdata *conn); -bool Curl_sendpipe_head(struct SessionHandle *data, +bool Curl_sendpipe_head(struct Curl_easy *data, struct connectdata *conn); #endif /* HEADER_CURL_PIPELINE_H */ diff --git a/contrib/curl/lib/pop3.c b/contrib/curl/lib/pop3.c index a6b2c3f7..3feb3be8 100644 --- a/contrib/curl/lib/pop3.c +++ b/contrib/curl/lib/pop3.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -70,16 +70,14 @@ #include "http.h" /* for HTTP proxy tunnel stuff */ #include "socks.h" #include "pop3.h" - #include "strtoofft.h" -#include "strequal.h" +#include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" -#include "rawstr.h" #include "curl_sasl.h" #include "curl_md5.h" #include "warnless.h" @@ -106,7 +104,7 @@ static CURLcode pop3_parse_custom_request(struct connectdata *conn); static CURLcode pop3_perform_auth(struct connectdata *conn, const char *mech, const char *initresp); static CURLcode pop3_continue_auth(struct connectdata *conn, const char *resp); -static void pop3_get_message(char *buffer, char** outptr); +static void pop3_get_message(char *buffer, char **outptr); /* * POP3 protocol handler. @@ -129,7 +127,8 @@ const struct Curl_handler Curl_handler_pop3 = { ZERO_NULL, /* readwrite */ PORT_POP3, /* defport */ CURLPROTO_POP3, /* protocol */ - PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */ + PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ + PROTOPT_URLOPTIONS }; #ifdef USE_SSL @@ -155,7 +154,7 @@ const struct Curl_handler Curl_handler_pop3s = { PORT_POP3S, /* defport */ CURLPROTO_POP3S, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_SSL - | PROTOPT_NOURLQUERY /* flags */ + | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */ }; #endif @@ -292,10 +291,10 @@ static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len, * * Gets the authentication message from the response buffer. */ -static void pop3_get_message(char *buffer, char** outptr) +static void pop3_get_message(char *buffer, char **outptr) { size_t len = 0; - char* message = NULL; + char *message = NULL; /* Find the start of the message */ for(message = buffer + 2; *message == ' ' || *message == '\t'; message++) @@ -597,7 +596,7 @@ static CURLcode pop3_perform_authentication(struct connectdata *conn) static CURLcode pop3_perform_command(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; const char *command = NULL; @@ -653,7 +652,7 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct pop3_conn *pop3c = &conn->proto.pop3c; const char *line = data->state.buffer; size_t len = strlen(line); @@ -663,7 +662,7 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, if(pop3code != '+') { failf(data, "Got unexpected pop3-server response"); - result = CURLE_FTP_WEIRD_SERVER_REPLY; + result = CURLE_WEIRD_SERVER_REPLY; } else { /* Does the server support APOP authentication? */ @@ -704,7 +703,7 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct pop3_conn *pop3c = &conn->proto.pop3c; const char *line = data->state.buffer; size_t len = strlen(line); @@ -795,13 +794,13 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(pop3code != '+') { if(data->set.use_ssl != CURLUSESSL_TRY) { - failf(data, "STARTTLS denied. %c", pop3code); + failf(data, "STARTTLS denied"); result = CURLE_USE_SSL_FAILED; } else @@ -819,7 +818,7 @@ static CURLcode pop3_state_auth_resp(struct connectdata *conn, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct pop3_conn *pop3c = &conn->proto.pop3c; saslprogress progress; @@ -859,7 +858,7 @@ static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -880,7 +879,7 @@ static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -903,7 +902,7 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -924,7 +923,7 @@ static CURLcode pop3_state_command_resp(struct connectdata *conn, pop3state instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; struct pop3_conn *pop3c = &conn->proto.pop3c; struct pingpong *pp = &pop3c->pp; @@ -1078,12 +1077,12 @@ static CURLcode pop3_block_statemach(struct connectdata *conn) return result; } -/* Allocate and initialize the POP3 struct for the current SessionHandle if +/* Allocate and initialize the POP3 struct for the current Curl_easy if required */ static CURLcode pop3_init(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3; pop3 = data->req.protop = calloc(sizeof(struct POP3), 1); @@ -1160,7 +1159,7 @@ static CURLcode pop3_done(struct connectdata *conn, CURLcode status, bool premature) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; (void)premature; @@ -1324,7 +1323,7 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn, { CURLcode result = CURLE_OK; bool connected = FALSE; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Make sure size is unknown at this point */ data->req.size = -1; @@ -1347,7 +1346,7 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn, static CURLcode pop3_setup_connection(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Initialise the POP3 layer */ CURLcode result = pop3_init(conn); @@ -1412,11 +1411,11 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn) while(*ptr && *ptr != ';') ptr++; - if(strnequal(key, "AUTH=", 5)) { + if(strncasecompare(key, "AUTH=", 5)) { result = Curl_sasl_parse_url_auth_option(&pop3c->sasl, value, ptr - value); - if(result && strnequal(value, "+APOP", ptr - value)) { + if(result && strncasecompare(value, "+APOP", ptr - value)) { pop3c->preftype = POP3_TYPE_APOP; pop3c->sasl.prefmech = SASL_AUTH_NONE; result = CURLE_OK; @@ -1454,7 +1453,7 @@ static CURLcode pop3_parse_url_options(struct connectdata *conn) static CURLcode pop3_parse_url_path(struct connectdata *conn) { /* The POP3 struct is already initialised in pop3_connect() */ - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; const char *path = data->state.path; @@ -1471,7 +1470,7 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn) static CURLcode pop3_parse_custom_request(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct POP3 *pop3 = data->req.protop; const char *custom = data->set.str[STRING_CUSTOMREQUEST]; @@ -1493,7 +1492,7 @@ CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread) { /* This code could be made into a special function in the handler struct */ CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SingleRequest *k = &data->req; struct pop3_conn *pop3c = &conn->proto.pop3c; @@ -1574,7 +1573,7 @@ CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread) if(prev) { /* If the partial match was the CRLF and dot then only write the CRLF as the server would have inserted the dot */ - result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB, + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, strip_dot ? prev - 1 : prev); if(result) diff --git a/contrib/curl/lib/pop3.h b/contrib/curl/lib/pop3.h index 2d961016..a8e697cd 100644 --- a/contrib/curl/lib/pop3.h +++ b/contrib/curl/lib/pop3.h @@ -45,9 +45,9 @@ typedef enum { POP3_LAST /* never used */ } pop3state; -/* This POP3 struct is used in the SessionHandle. All POP3 data that is +/* This POP3 struct is used in the Curl_easy. All POP3 data that is connection-oriented must be in pop3_conn to properly deal with the fact that - perhaps the SessionHandle is changed between the times the connection is + perhaps the Curl_easy is changed between the times the connection is used. */ struct POP3 { curl_pp_transfer transfer; diff --git a/contrib/curl/lib/progress.c b/contrib/curl/lib/progress.c index 713ab085..60627b2a 100644 --- a/contrib/curl/lib/progress.c +++ b/contrib/curl/lib/progress.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -133,7 +133,7 @@ static char *max5data(curl_off_t bytes, char *max5) int Curl_pgrsDone(struct connectdata *conn) { int rc; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; data->progress.lastshow=0; rc = Curl_pgrsUpdate(conn); /* the final (forced) update */ if(rc) @@ -150,7 +150,7 @@ int Curl_pgrsDone(struct connectdata *conn) } /* reset all times except redirect, and reset the known transfer sizes */ -void Curl_pgrsResetTimesSizes(struct SessionHandle *data) +void Curl_pgrsResetTimesSizes(struct Curl_easy *data) { data->progress.t_nslookup = 0.0; data->progress.t_connect = 0.0; @@ -161,7 +161,7 @@ void Curl_pgrsResetTimesSizes(struct SessionHandle *data) Curl_pgrsSetUploadSize(data, -1); } -void Curl_pgrsTime(struct SessionHandle *data, timerid timer) +void Curl_pgrsTime(struct Curl_easy *data, timerid timer) { struct timeval now = Curl_tvnow(); @@ -212,25 +212,102 @@ void Curl_pgrsTime(struct SessionHandle *data, timerid timer) } } -void Curl_pgrsStartNow(struct SessionHandle *data) +void Curl_pgrsStartNow(struct Curl_easy *data) { data->progress.speeder_c = 0; /* reset the progress meter display */ data->progress.start = Curl_tvnow(); + data->progress.ul_limit_start.tv_sec = 0; + data->progress.ul_limit_start.tv_usec = 0; + data->progress.dl_limit_start.tv_sec = 0; + data->progress.dl_limit_start.tv_usec = 0; /* clear all bits except HIDE and HEADERS_OUT */ data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT; } -void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size) +/* + * This is used to handle speed limits, calculating how much milliseconds we + * need to wait until we're back under the speed limit, if needed. + * + * The way it works is by having a "starting point" (time & amount of data + * transfered by then) used in the speed computation, to be used instead of the + * start of the transfer. + * This starting point is regularly moved as transfer goes on, to keep getting + * accurate values (instead of average over the entire tranfer). + * + * This function takes the current amount of data transfered, the amount at the + * starting point, the limit (in bytes/s), the time of the starting point and + * the current time. + * + * Returns -1 if no waiting is needed (not enough data transfered since + * starting point yet), 0 when no waiting is needed but the starting point + * should be reset (to current), or the number of milliseconds to wait to get + * back under the speed limit. + */ +long Curl_pgrsLimitWaitTime(curl_off_t cursize, + curl_off_t startsize, + curl_off_t limit, + struct timeval start, + struct timeval now) { + curl_off_t size = cursize - startsize; + time_t minimum; + time_t actual; + + /* we don't have a starting point yet -- return 0 so it gets (re)set */ + if(start.tv_sec == 0 && start.tv_usec == 0) + return 0; + + /* not enough data yet */ + if(size < limit) + return -1; + + minimum = (time_t) (CURL_OFF_T_C(1000) * size / limit); + actual = Curl_tvdiff(now, start); + + if(actual < minimum) + /* this is a conversion on some systems (64bit time_t => 32bit long) */ + return (long)(minimum - actual); + else + return 0; +} + +void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size) +{ + struct timeval now = Curl_tvnow(); + data->progress.downloaded = size; + + /* download speed limit */ + if((data->set.max_recv_speed > 0) && + (Curl_pgrsLimitWaitTime(data->progress.downloaded, + data->progress.dl_limit_size, + data->set.max_recv_speed, + data->progress.dl_limit_start, + now) == 0)) { + data->progress.dl_limit_start = now; + data->progress.dl_limit_size = size; + } } -void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size) +void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size) { + struct timeval now = Curl_tvnow(); + data->progress.uploaded = size; + + /* upload speed limit */ + if((data->set.max_send_speed > 0) && + (Curl_pgrsLimitWaitTime(data->progress.uploaded, + data->progress.ul_limit_size, + data->set.max_send_speed, + data->progress.ul_limit_start, + now) == 0)) { + data->progress.ul_limit_start = now; + data->progress.ul_limit_size = size; + } } -void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size) +void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size) { if(size >= 0) { data->progress.size_dl = size; @@ -242,7 +319,7 @@ void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size) } } -void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size) +void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size) { if(size >= 0) { data->progress.size_ul = size; @@ -269,7 +346,7 @@ int Curl_pgrsUpdate(struct connectdata *conn) curl_off_t total_transfer; curl_off_t total_expected_transfer; curl_off_t timespent; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int nowindex = data->progress.speeder_c% CURR_TIME; int checkindex; int countindex; /* amount of seconds stored in the speeder array */ @@ -284,9 +361,7 @@ int Curl_pgrsUpdate(struct connectdata *conn) now = Curl_tvnow(); /* what time is it */ /* The time spent so far (from the start) */ - data->progress.timespent = - (double)(now.tv_sec - data->progress.start.tv_sec) + - (double)(now.tv_usec - data->progress.start.tv_usec)/1000000.0; + data->progress.timespent = curlx_tvdiff_secs(now, data->progress.start); timespent = (curl_off_t)data->progress.timespent; /* The average download speed this far */ @@ -300,7 +375,7 @@ int Curl_pgrsUpdate(struct connectdata *conn) (data->progress.timespent>0?data->progress.timespent:1)); /* Calculations done at most once a second, unless end is reached */ - if(data->progress.lastshow != (long)now.tv_sec) { + if(data->progress.lastshow != now.tv_sec) { shownow = TRUE; data->progress.lastshow = now.tv_sec; @@ -327,7 +402,7 @@ int Curl_pgrsUpdate(struct connectdata *conn) /* first of all, we don't do this if there's no counted seconds yet */ if(countindex) { - long span_ms; + time_t span_ms; /* Get the index position to compare with the 'nowindex' position. Get the oldest entry possible. While we have less than CURR_TIME diff --git a/contrib/curl/lib/progress.h b/contrib/curl/lib/progress.h index ea00afa9..155ff04f 100644 --- a/contrib/curl/lib/progress.h +++ b/contrib/curl/lib/progress.h @@ -41,15 +41,19 @@ typedef enum { } timerid; int Curl_pgrsDone(struct connectdata *); -void Curl_pgrsStartNow(struct SessionHandle *data); -void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size); -void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size); -void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size); -void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size); +void Curl_pgrsStartNow(struct Curl_easy *data); +void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size); +void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size); +void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size); +void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size); int Curl_pgrsUpdate(struct connectdata *); -void Curl_pgrsResetTimesSizes(struct SessionHandle *data); -void Curl_pgrsTime(struct SessionHandle *data, timerid timer); - +void Curl_pgrsResetTimesSizes(struct Curl_easy *data); +void Curl_pgrsTime(struct Curl_easy *data, timerid timer); +long Curl_pgrsLimitWaitTime(curl_off_t cursize, + curl_off_t startsize, + curl_off_t limit, + struct timeval start, + struct timeval now); /* Don't show progress for sizes smaller than: */ #define LEAST_SIZE_PROGRESS BUFSIZE diff --git a/contrib/curl/lib/rand.c b/contrib/curl/lib/rand.c new file mode 100644 index 00000000..4da37b9d --- /dev/null +++ b/contrib/curl/lib/rand.c @@ -0,0 +1,132 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_FCNTL_H +#include +#endif + +#include +#include "vtls/vtls.h" +#include "sendf.h" +#include "rand.h" + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + +static CURLcode randit(struct Curl_easy *data, unsigned int *rnd) +{ + unsigned int r; + CURLcode result = CURLE_OK; + static unsigned int randseed; + static bool seeded = FALSE; + +#ifdef CURLDEBUG + char *force_entropy = getenv("CURL_ENTROPY"); + if(force_entropy) { + if(!seeded) { + size_t elen = strlen(force_entropy); + size_t clen = sizeof(randseed); + size_t min = elen < clen ? elen : clen; + memcpy((char *)&randseed, force_entropy, min); + seeded = TRUE; + } + else + randseed++; + *rnd = randseed; + return CURLE_OK; + } +#endif + + /* data may be NULL! */ + result = Curl_ssl_random(data, (unsigned char *)rnd, sizeof(*rnd)); + if(result != CURLE_NOT_BUILT_IN) + /* only if there is no random funtion in the TLS backend do the non crypto + version, otherwise return result */ + return result; + + /* ---- non-cryptographic version following ---- */ + +#ifdef RANDOM_FILE + if(!seeded) { + /* if there's a random file to read a seed from, use it */ + int fd = open(RANDOM_FILE, O_RDONLY); + if(fd > -1) { + /* read random data into the randseed variable */ + ssize_t nread = read(fd, &randseed, sizeof(randseed)); + if(nread == sizeof(randseed)) + seeded = TRUE; + close(fd); + } + } +#endif + + if(!seeded) { + struct timeval now = curlx_tvnow(); + infof(data, "WARNING: Using weak random seed\n"); + randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec; + randseed = randseed * 1103515245 + 12345; + randseed = randseed * 1103515245 + 12345; + randseed = randseed * 1103515245 + 12345; + seeded = TRUE; + } + + /* Return an unsigned 32-bit pseudo-random number. */ + r = randseed = randseed * 1103515245 + 12345; + *rnd = (r << 16) | ((r >> 16) & 0xFFFF); + return CURLE_OK; +} + +/* + * Curl_rand() stores 'num' number of random unsigned integers in the buffer + * 'rndptr' points to. + * + * If libcurl is built without TLS support or with a TLS backend that lacks a + * proper random API (Gskit, PolarSSL or mbedTLS), this function will use + * "weak" random. + * + * When built *with* TLS support and a backend that offers strong random, it + * will return error if it cannot provide strong random values. + * + * NOTE: 'data' may be passed in as NULL when coming from external API without + * easy handle! + * + */ + +CURLcode Curl_rand(struct Curl_easy *data, unsigned int *rndptr, + unsigned int num) +{ + CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT; + unsigned int i; + + assert(num > 0); + + for(i = 0; i < num; i++) { + result = randit(data, rndptr++); + if(result) + return result; + } + return result; +} diff --git a/contrib/curl/lib/strequal.h b/contrib/curl/lib/rand.h similarity index 55% rename from contrib/curl/lib/strequal.h rename to contrib/curl/lib/rand.h index ff56df51..0f898612 100644 --- a/contrib/curl/lib/strequal.h +++ b/contrib/curl/lib/rand.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_STREQUAL_H -#define HEADER_CURL_STREQUAL_H +#ifndef HEADER_CURL_RAND_H +#define HEADER_CURL_RAND_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,10 +22,22 @@ * ***************************************************************************/ -#include - -#define strequal(a,b) curl_strequal(a,b) -#define strnequal(a,b,c) curl_strnequal(a,b,c) - -#endif /* HEADER_CURL_STREQUAL_H */ +/* + * Curl_rand() stores 'num' number of random unsigned integers in the buffer + * 'rnd' points to. + * + * If libcurl is built without TLS support or with a TLS backend that lacks a + * proper random API (Gskit, PolarSSL or mbedTLS), this function will use + * "weak" random. + * + * When built *with* TLS support and a backend that offers strong random, it + * will return error if it cannot provide strong random values. + * + * NOTE: 'data' may be passed in as NULL when coming from external API without + * easy handle! + * + */ +CURLcode Curl_rand(struct Curl_easy *data, unsigned int *rnd, + unsigned int num); +#endif /* HEADER_CURL_RAND_H */ diff --git a/contrib/curl/lib/rtsp.c b/contrib/curl/lib/rtsp.c index 5cb10448..65c6c3b0 100644 --- a/contrib/curl/lib/rtsp.c +++ b/contrib/curl/lib/rtsp.c @@ -33,9 +33,10 @@ #include "url.h" #include "progress.h" #include "rtsp.h" -#include "rawstr.h" +#include "strcase.h" #include "select.h" #include "connect.h" +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -73,7 +74,7 @@ static int rtsp_getsock_do(struct connectdata *conn, * data is parsed and k->str is moved up * readmore: whether or not the RTP parser needs more data right away */ -static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data, +static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, bool *readmore); @@ -139,7 +140,7 @@ static CURLcode rtsp_setup_connection(struct connectdata *conn) * want to block the application forever while receiving a stream. Therefore, * we cannot assume that an RTSP socket is dead just because it is readable. * - * Instead, if it is readable, run Curl_getconnectinfo() to peek at the socket + * Instead, if it is readable, run Curl_connalive() to peek at the socket * and distinguish between closed and data. */ bool Curl_rtsp_connisdead(struct connectdata *check) @@ -147,7 +148,7 @@ bool Curl_rtsp_connisdead(struct connectdata *check) int sval; bool ret_val = TRUE; - sval = Curl_socket_ready(check->sock[FIRSTSOCKET], CURL_SOCKET_BAD, 0); + sval = SOCKET_READABLE(check->sock[FIRSTSOCKET], 0); if(sval == 0) { /* timeout */ ret_val = FALSE; @@ -156,12 +157,9 @@ bool Curl_rtsp_connisdead(struct connectdata *check) /* socket is in an error state */ ret_val = TRUE; } - else if((sval & CURL_CSELECT_IN) && check->data) { - /* readable with no error. could be closed or could be alive but we can - only check if we have a proper SessionHandle for the connection */ - curl_socket_t connectinfo = Curl_getconnectinfo(check->data, &check); - if(connectinfo != CURL_SOCKET_BAD) - ret_val = FALSE; + else if(sval & CURL_CSELECT_IN) { + /* readable with no error. could still be closed */ + ret_val = !Curl_connalive(check); } return ret_val; @@ -170,7 +168,7 @@ bool Curl_rtsp_connisdead(struct connectdata *check) static CURLcode rtsp_connect(struct connectdata *conn, bool *done) { CURLcode httpStatus; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; httpStatus = Curl_http_connect(conn, done); @@ -196,7 +194,7 @@ static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead) static CURLcode rtsp_done(struct connectdata *conn, CURLcode status, bool premature) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct RTSP *rtsp = data->req.protop; CURLcode httpStatus; long CSeq_sent; @@ -230,7 +228,7 @@ static CURLcode rtsp_done(struct connectdata *conn, static CURLcode rtsp_do(struct connectdata *conn, bool *done) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result=CURLE_OK; Curl_RtspReq rtspreq = data->set.rtspreq; struct RTSP *rtsp = data->req.protop; @@ -488,7 +486,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM * with basic and digest, it will be freed anyway by the next request */ - Curl_safefree (conn->allocptr.userpwd); + Curl_safefree(conn->allocptr.userpwd); conn->allocptr.userpwd = NULL; if(result) @@ -600,7 +598,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) } -static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data, +static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, bool *readmore) { @@ -614,9 +612,9 @@ static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data, if(rtspc->rtp_buf) { /* There was some leftover data the last time. Merge buffers */ - char *newptr = realloc(rtspc->rtp_buf, rtspc->rtp_bufsize + *nread); + char *newptr = Curl_saferealloc(rtspc->rtp_buf, + rtspc->rtp_bufsize + *nread); if(!newptr) { - Curl_safefree(rtspc->rtp_buf); rtspc->rtp_buf = NULL; rtspc->rtp_bufsize = 0; return CURLE_OUT_OF_MEMORY; @@ -731,12 +729,12 @@ static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data, static CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; size_t wrote; curl_write_callback writeit; if(len == 0) { - failf (data, "Cannot write a 0 size RTP packet."); + failf(data, "Cannot write a 0 size RTP packet."); return CURLE_WRITE_ERROR; } @@ -744,12 +742,12 @@ CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len) wrote = writeit(ptr, 1, len, data->set.rtp_out); if(CURL_WRITEFUNC_PAUSE == wrote) { - failf (data, "Cannot pause RTP"); + failf(data, "Cannot pause RTP"); return CURLE_WRITE_ERROR; } if(wrote != len) { - failf (data, "Failed writing RTP data"); + failf(data, "Failed writing RTP data"); return CURLE_WRITE_ERROR; } @@ -759,7 +757,7 @@ CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len) CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; long CSeq = 0; if(checkprefix("CSeq:", header)) { @@ -796,19 +794,15 @@ CURLcode Curl_rtsp_parseheader(struct connectdata *conn, } } else { - /* If the Session ID is not set, and we find it in a response, then - set it */ - - /* The session ID can be an alphanumeric or a 'safe' character + /* If the Session ID is not set, and we find it in a response, then set + * it. * - * RFC 2326 15.1 Base Syntax: - * safe = "\$" | "-" | "_" | "." | "+" - * */ + * Allow any non whitespace content, up to the field seperator or end of + * line. RFC 2326 isn't 100% clear on the session ID and for example + * gstreamer does url-encoded session ID's not covered by the standard. + */ char *end = start; - while(*end && - (ISALNUM(*end) || *end == '-' || *end == '_' || *end == '.' || - *end == '+' || - (*end == '\\' && *(end + 1) && *(end + 1) == '$' && (++end, 1)))) + while(*end && *end != ';' && !ISSPACE(*end)) end++; /* Copy the id substring into a new buffer */ diff --git a/contrib/curl/lib/security.c b/contrib/curl/lib/security.c index 014bbf1b..f4a87634 100644 --- a/contrib/curl/lib/security.c +++ b/contrib/curl/lib/security.c @@ -60,9 +60,9 @@ #include "curl_sec.h" #include "ftp.h" #include "sendf.h" -#include "rawstr.h" +#include "strcase.h" #include "warnless.h" - +#include "strdup.h" /* The last #include file should be: */ #include "memdebug.h" @@ -88,7 +88,8 @@ name_to_level(const char *name) /* Convert a protocol |level| to its char representation. We take an int to catch programming mistakes. */ -static char level_to_char(int level) { +static char level_to_char(int level) +{ switch(level) { case PROT_CLEAR: return 'C'; @@ -122,7 +123,7 @@ static int ftp_send_command(struct connectdata *conn, const char *message, ...) vsnprintf(print_buffer, sizeof(print_buffer), message, args); va_end(args); - if(Curl_ftpsendf(conn, print_buffer)) { + if(Curl_ftpsend(conn, print_buffer)) { ftp_code = -1; } else { @@ -192,15 +193,18 @@ static CURLcode read_data(struct connectdata *conn, struct krb5buffer *buf) { int len; - void* tmp; + void *tmp = NULL; CURLcode result; result = socket_read(fd, &len, sizeof(len)); if(result) return result; - len = ntohl(len); - tmp = realloc(buf->data, len); + if(len) { + /* only realloc if there was a length */ + len = ntohl(len); + tmp = Curl_saferealloc(buf->data, len); + } if(tmp == NULL) return CURLE_OUT_OF_MEMORY; @@ -219,7 +223,7 @@ buffer_read(struct krb5buffer *buf, void *data, size_t len) { if(buf->size - buf->index < len) len = buf->size - buf->index; - memcpy(data, (char*)buf->data + buf->index, len); + memcpy(data, (char *)buf->data + buf->index, len); buf->index += len; return len; } @@ -288,7 +292,7 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd, prot_level = conn->command_prot; } bytes = conn->mech->encode(conn->app_data, from, length, prot_level, - (void**)&buffer); + (void **)&buffer); if(!buffer || bytes <= 0) return; /* error */ @@ -363,6 +367,10 @@ int Curl_sec_read_msg(struct connectdata *conn, char *buffer, size_t decoded_sz = 0; CURLcode error; + if(!conn->mech) + /* not inititalized, return error */ + return -1; + DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); error = Curl_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz); @@ -408,7 +416,7 @@ int Curl_sec_read_msg(struct connectdata *conn, char *buffer, static int sec_set_protection_level(struct connectdata *conn) { int code; - char* pbsz; + char *pbsz; static unsigned int buffer_size = 1 << 20; /* 1048576 */ enum protection_level level = conn->request_data_prot; @@ -476,7 +484,7 @@ Curl_sec_request_prot(struct connectdata *conn, const char *level) static CURLcode choose_mech(struct connectdata *conn) { int ret; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; void *tmp_allocation; const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech; diff --git a/contrib/curl/lib/select.c b/contrib/curl/lib/select.c index abf55d87..03af645e 100644 --- a/contrib/curl/lib/select.c +++ b/contrib/curl/lib/select.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -51,15 +51,14 @@ #include "warnless.h" /* Convenience local macros */ - -#define elapsed_ms (int)curlx_tvdiff(curlx_tvnow(), initial_tv) +#define ELAPSED_MS() (int)curlx_tvdiff(curlx_tvnow(), initial_tv) int Curl_ack_eintr = 0; -#define error_not_EINTR (Curl_ack_eintr || error != EINTR) +#define ERROR_NOT_EINTR(error) (Curl_ack_eintr || error != EINTR) /* * Internal function used for waiting a specific amount of ms - * in Curl_socket_ready() and Curl_poll() when no file descriptor + * in Curl_socket_check() and Curl_poll() when no file descriptor * is provided to wait on, just being used to delay execution. * WinSock select() and poll() timeout mechanisms need a valid * socket descriptor in a not null file descriptor set to work. @@ -109,9 +108,9 @@ int Curl_wait_ms(int timeout_ms) if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; - pending_ms = timeout_ms - elapsed_ms; + pending_ms = timeout_ms - ELAPSED_MS(); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; @@ -146,7 +145,7 @@ int Curl_wait_ms(int timeout_ms) int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ curl_socket_t readfd1, curl_socket_t writefd, /* socket to write to */ - long timeout_ms) /* milliseconds to wait */ + time_t timeout_ms) /* milliseconds to wait */ { #ifdef HAVE_POLL_FINE struct pollfd pfd[3]; @@ -165,6 +164,12 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ int r; int ret; +#if SIZEOF_LONG != SIZEOF_INT + /* wrap-around precaution */ + if(timeout_ms >= INT_MAX) + timeout_ms = INT_MAX; +#endif + if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) { /* no sockets, just wait */ @@ -213,10 +218,10 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; if(timeout_ms > 0) { - pending_ms = (int)(timeout_ms - elapsed_ms); + pending_ms = (int)(timeout_ms - ELAPSED_MS()); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; @@ -328,10 +333,10 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */ if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; if(timeout_ms > 0) { - pending_ms = timeout_ms - elapsed_ms; + pending_ms = (int)(timeout_ms - ELAPSED_MS()); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; @@ -434,10 +439,10 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; if(timeout_ms > 0) { - pending_ms = timeout_ms - elapsed_ms; + pending_ms = (int)(timeout_ms - ELAPSED_MS()); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; @@ -521,10 +526,10 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) if(r != -1) break; error = SOCKERRNO; - if(error && error_not_EINTR) + if(error && ERROR_NOT_EINTR(error)) break; if(timeout_ms > 0) { - pending_ms = timeout_ms - elapsed_ms; + pending_ms = timeout_ms - ELAPSED_MS(); if(pending_ms <= 0) { r = 0; /* Simulate a "call timed out" case */ break; diff --git a/contrib/curl/lib/select.h b/contrib/curl/lib/select.h index 695bb69c..e247bd9d 100644 --- a/contrib/curl/lib/select.h +++ b/contrib/curl/lib/select.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -73,11 +73,12 @@ struct pollfd int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2, curl_socket_t writefd, - long timeout_ms); + time_t timeout_ms); -/* provide the former API internally */ -#define Curl_socket_ready(x,y,z) \ - Curl_socket_check(x, CURL_SOCKET_BAD, y, z) +#define SOCKET_READABLE(x,z) \ + Curl_socket_check(x, CURL_SOCKET_BAD, CURL_SOCKET_BAD, z) +#define SOCKET_WRITABLE(x,z) \ + Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, x, z) int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms); diff --git a/contrib/curl/lib/sendf.c b/contrib/curl/lib/sendf.c index 22f3bf27..76016978 100644 --- a/contrib/curl/lib/sendf.c +++ b/contrib/curl/lib/sendf.c @@ -46,7 +46,7 @@ * blocks of data. Remaining, bare CRs are changed to LFs. The possibly new * size of the data is returned. */ -static size_t convert_lineends(struct SessionHandle *data, +static size_t convert_lineends(struct Curl_easy *data, char *startPtr, size_t size) { char *inPtr, *outPtr; @@ -122,6 +122,13 @@ static size_t convert_lineends(struct SessionHandle *data, #endif /* CURL_DO_LINEEND_CONV */ #ifdef USE_RECV_BEFORE_SEND_WORKAROUND +bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex) +{ + struct postponed_data * const psnd = &(conn->postponed[sockindex]); + return psnd->buffer && psnd->allocated_size && + psnd->recv_size > psnd->recv_processed; +} + static void pre_receive_plain(struct connectdata *conn, int num) { const curl_socket_t sockfd = conn->sock[num]; @@ -201,13 +208,19 @@ static ssize_t get_pre_recved(struct connectdata *conn, int num, char *buf, } #else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ /* Use "do-nothing" macros instead of functions when workaround not used */ +bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex) +{ + (void)conn; + (void)sockindex; + return false; +} #define pre_receive_plain(c,n) do {} WHILE_FALSE #define get_pre_recved(c,n,b,l) 0 #endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */ /* Curl_infof() is for info message along the way */ -void Curl_infof(struct SessionHandle *data, const char *fmt, ...) +void Curl_infof(struct Curl_easy *data, const char *fmt, ...) { if(data && data->set.verbose) { va_list ap; @@ -225,7 +238,7 @@ void Curl_infof(struct SessionHandle *data, const char *fmt, ...) * The message SHALL NOT include any LF or CR. */ -void Curl_failf(struct SessionHandle *data, const char *fmt, ...) +void Curl_failf(struct Curl_easy *data, const char *fmt, ...) { va_list ap; size_t len; @@ -253,7 +266,7 @@ void Curl_failf(struct SessionHandle *data, const char *fmt, ...) CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn, const char *fmt, ...) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; ssize_t bytes_written; size_t write_len; CURLcode result = CURLE_OK; @@ -452,7 +465,7 @@ ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf, return nread; } -static CURLcode pausewrite(struct SessionHandle *data, +static CURLcode pausewrite(struct Curl_easy *data, int type, /* what type of data */ const char *ptr, size_t len) @@ -488,10 +501,10 @@ static CURLcode pausewrite(struct SessionHandle *data, */ CURLcode Curl_client_chop_write(struct connectdata *conn, int type, - char * ptr, + char *ptr, size_t len) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_write_callback writeheader = NULL; curl_write_callback writebody = NULL; @@ -571,7 +584,7 @@ CURLcode Curl_client_chop_write(struct connectdata *conn, return pausewrite(data, CLIENTWRITE_HEADER, ptr, len); if(wrote != chunklen) { - failf (data, "Failed writing header"); + failf(data, "Failed writing header"); return CURLE_WRITE_ERROR; } } @@ -598,7 +611,7 @@ CURLcode Curl_client_write(struct connectdata *conn, char *ptr, size_t len) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(0 == len) len = strlen(ptr); @@ -692,7 +705,7 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */ } /* If we come here, it means that there is no data to read from the buffer, * so we read from the socket */ - bytesfromsocket = CURLMIN(sizerequested, BUFSIZE * sizeof (char)); + bytesfromsocket = CURLMIN(sizerequested, BUFSIZE * sizeof(char)); buffertofill = conn->master_buffer; } else { @@ -718,7 +731,7 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */ } /* return 0 on success */ -static int showit(struct SessionHandle *data, curl_infotype type, +static int showit(struct Curl_easy *data, curl_infotype type, char *ptr, size_t size) { static const char s_infotype[CURLINFO_END][3] = { @@ -787,7 +800,7 @@ static int showit(struct SessionHandle *data, curl_infotype type, return 0; } -int Curl_debug(struct SessionHandle *data, curl_infotype type, +int Curl_debug(struct Curl_easy *data, curl_infotype type, char *ptr, size_t size, struct connectdata *conn) { @@ -796,7 +809,7 @@ int Curl_debug(struct SessionHandle *data, curl_infotype type, char buffer[160]; const char *t=NULL; const char *w="Data"; - switch (type) { + switch(type) { case CURLINFO_HEADER_IN: w = "Header"; /* FALLTHROUGH */ diff --git a/contrib/curl/lib/sendf.h b/contrib/curl/lib/sendf.h index 48e9444c..fbe4f99c 100644 --- a/contrib/curl/lib/sendf.h +++ b/contrib/curl/lib/sendf.h @@ -26,8 +26,8 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *, const char *fmt, ...); -void Curl_infof(struct SessionHandle *, const char *fmt, ...); -void Curl_failf(struct SessionHandle *, const char *fmt, ...); +void Curl_infof(struct Curl_easy *, const char *fmt, ...); +void Curl_failf(struct Curl_easy *, const char *fmt, ...); #if defined(CURL_DISABLE_VERBOSE_STRINGS) @@ -56,6 +56,8 @@ CURLcode Curl_client_chop_write(struct connectdata *conn, int type, char *ptr, CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr, size_t len) WARN_UNUSED_RESULT; +bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex); + /* internal read-function, does plain socket only */ CURLcode Curl_read_plain(curl_socket_t sockfd, char *buf, @@ -84,7 +86,7 @@ CURLcode Curl_write_plain(struct connectdata *conn, ssize_t *written); /* the function used to output verbose information */ -int Curl_debug(struct SessionHandle *handle, curl_infotype type, +int Curl_debug(struct Curl_easy *handle, curl_infotype type, char *data, size_t size, struct connectdata *conn); diff --git a/contrib/curl/lib/setup-os400.h b/contrib/curl/lib/setup-os400.h index e32b72f2..a3c2a7bd 100644 --- a/contrib/curl/lib/setup-os400.h +++ b/contrib/curl/lib/setup-os400.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -41,18 +41,18 @@ typedef unsigned long u_int32_t; #include #include -extern int Curl_getaddrinfo_a(const char * nodename, - const char * servname, - const struct addrinfo * hints, - struct addrinfo * * res); +extern int Curl_getaddrinfo_a(const char *nodename, + const char *servname, + const struct addrinfo *hints, + struct addrinfo **res); #define getaddrinfo Curl_getaddrinfo_a -extern int Curl_getnameinfo_a(const struct sockaddr * sa, - curl_socklen_t salen, - char * nodename, curl_socklen_t nodenamelen, - char * servname, curl_socklen_t servnamelen, - int flags); +extern int Curl_getnameinfo_a(const struct sockaddr *sa, + curl_socklen_t salen, + char *nodename, curl_socklen_t nodenamelen, + char *servname, curl_socklen_t servnamelen, + int flags); #define getnameinfo Curl_getnameinfo_a @@ -79,7 +79,7 @@ extern int Curl_gsk_secure_soc_init(gsk_handle my_session_handle); extern int Curl_gsk_attribute_set_buffer_a(gsk_handle my_gsk_handle, GSK_BUF_ID bufID, - const char * buffer, + const char *buffer, int bufSize); #define gsk_attribute_set_buffer Curl_gsk_attribute_set_buffer_a @@ -95,29 +95,29 @@ extern int Curl_gsk_attribute_set_numeric_value(gsk_handle my_gsk_handle, extern int Curl_gsk_attribute_set_callback(gsk_handle my_gsk_handle, GSK_CALLBACK_ID callBackID, - void * callBackAreaPtr); + void *callBackAreaPtr); #define gsk_attribute_set_callback Curl_gsk_attribute_set_callback extern int Curl_gsk_attribute_get_buffer_a(gsk_handle my_gsk_handle, GSK_BUF_ID bufID, - const char * * buffer, - int * bufSize); + const char **buffer, + int *bufSize); #define gsk_attribute_get_buffer Curl_gsk_attribute_get_buffer_a extern int Curl_gsk_attribute_get_enum(gsk_handle my_gsk_handle, GSK_ENUM_ID enumID, - GSK_ENUM_VALUE * enumValue); + GSK_ENUM_VALUE *enumValue); #define gsk_attribute_get_enum Curl_gsk_attribute_get_enum extern int Curl_gsk_attribute_get_numeric_value(gsk_handle my_gsk_handle, GSK_NUM_ID numID, - int * numValue); + int *numValue); #define gsk_attribute_get_numeric_value Curl_gsk_attribute_get_numeric_value extern int Curl_gsk_attribute_get_cert_info(gsk_handle my_gsk_handle, GSK_CERT_ID certID, - const gsk_cert_data_elem * * certDataElem, - int * certDataElementCount); + const gsk_cert_data_elem **certDataElem, + int *certDataElementCount); #define gsk_attribute_get_cert_info Curl_gsk_attribute_get_cert_info extern int Curl_gsk_secure_soc_misc(gsk_handle my_session_handle, @@ -125,13 +125,13 @@ extern int Curl_gsk_secure_soc_misc(gsk_handle my_session_handle, #define gsk_secure_soc_misc Curl_gsk_secure_soc_misc extern int Curl_gsk_secure_soc_read(gsk_handle my_session_handle, - char * readBuffer, - int readBufSize, int * amtRead); + char *readBuffer, + int readBufSize, int *amtRead); #define gsk_secure_soc_read Curl_gsk_secure_soc_read extern int Curl_gsk_secure_soc_write(gsk_handle my_session_handle, - char * writeBuffer, - int writeBufSize, int * amtWritten); + char *writeBuffer, + int writeBufSize, int *amtWritten); #define gsk_secure_soc_write Curl_gsk_secure_soc_write extern const char * Curl_gsk_strerror_a(int gsk_return_value); @@ -202,10 +202,10 @@ extern OM_uint32 Curl_gss_delete_sec_context_a(OM_uint32 * minor_status, extern int Curl_os400_connect(int sd, struct sockaddr * destaddr, int addrlen); extern int Curl_os400_bind(int sd, struct sockaddr * localaddr, int addrlen); -extern int Curl_os400_sendto(int sd, char * buffer, int buflen, int flags, - struct sockaddr * dstaddr, int addrlen); -extern int Curl_os400_recvfrom(int sd, char * buffer, int buflen, int flags, - struct sockaddr * fromaddr, int * addrlen); +extern int Curl_os400_sendto(int sd, char *buffer, int buflen, int flags, + struct sockaddr * dstaddr, int addrlen); +extern int Curl_os400_recvfrom(int sd, char *buffer, int buflen, int flags, + struct sockaddr *fromaddr, int *addrlen); #define connect Curl_os400_connect #define bind Curl_os400_bind diff --git a/contrib/curl/lib/setup-vms.h b/contrib/curl/lib/setup-vms.h index 4b78e0bf..6c454aee 100644 --- a/contrib/curl/lib/setup-vms.h +++ b/contrib/curl/lib/setup-vms.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -41,7 +41,7 @@ # endif #endif #include - char * decc$getenv(const char * __name); +char *decc$getenv(const char *__name); #include #include @@ -79,23 +79,24 @@ # if __INITIAL_POINTER_SIZE == 32 /* Translate the path, but only if the path is a VMS file specification */ /* The translation is usually only needed for older versions of VMS */ -static char * vms_translate_path(const char * path) { -char * unix_path; -char * test_str; +static char *vms_translate_path(const char *path) +{ + char *unix_path; + char *test_str; - /* See if the result is in VMS format, if not, we are done */ - /* Assume that this is a PATH, not just some data */ - test_str = strpbrk(path, ":[<^"); - if(test_str == NULL) { - return (char *)path; - } + /* See if the result is in VMS format, if not, we are done */ + /* Assume that this is a PATH, not just some data */ + test_str = strpbrk(path, ":[<^"); + if(test_str == NULL) { + return (char *)path; + } - unix_path = decc$translate_vms(path); + unix_path = decc$translate_vms(path); - if((int)unix_path <= 0) { - /* We can not translate it, so return the original string */ - return (char *)path; - } + if((int)unix_path <= 0) { + /* We can not translate it, so return the original string */ + return (char *)path; + } } # else /* VMS translate path is actually not needed on the current 64 bit */ @@ -111,74 +112,74 @@ char * test_str; # endif #endif -static char * vms_getenv(const char * envvar) { - -char * result; -char * vms_path; - - /* first use the DECC getenv() function */ - result = decc$getenv(envvar); - if(result == NULL) { - return result; - } - - vms_path = result; - result = vms_translate_path(vms_path); - - /* note that if you backport this to use VAX C RTL, that the VAX C RTL */ - /* may do a malloc(2048) for each call to getenv(), so you will need */ - /* to add a free(vms_path) */ - /* Do not do a free() for DEC C RTL builds, which should be used for */ - /* VMS 5.5-2 and later, even if using GCC */ +static char *vms_getenv(const char *envvar) +{ + char *result; + char *vms_path; + /* first use the DECC getenv() function */ + result = decc$getenv(envvar); + if(result == NULL) { return result; + } + + vms_path = result; + result = vms_translate_path(vms_path); + + /* note that if you backport this to use VAX C RTL, that the VAX C RTL */ + /* may do a malloc(2048) for each call to getenv(), so you will need */ + /* to add a free(vms_path) */ + /* Do not do a free() for DEC C RTL builds, which should be used for */ + /* VMS 5.5-2 and later, even if using GCC */ + + return result; } static struct passwd vms_passwd_cache; -static struct passwd * vms_getpwuid(uid_t uid) { - -struct passwd * my_passwd; +static struct passwd * vms_getpwuid(uid_t uid) +{ + struct passwd * my_passwd; /* Hack needed to support 64 bit builds, decc_getpwnam is 32 bit only */ #ifdef __DECC # if __INITIAL_POINTER_SIZE -__char_ptr32 unix_path; + __char_ptr32 unix_path; # else -char * unix_path; + char *unix_path; # endif #else -char * unix_path; + char *unix_path; #endif - my_passwd = decc_getpwuid(uid); - if(my_passwd == NULL) { - return my_passwd; - } + my_passwd = decc_getpwuid(uid); + if(my_passwd == NULL) { + return my_passwd; + } - unix_path = vms_translate_path(my_passwd->pw_dir); + unix_path = vms_translate_path(my_passwd->pw_dir); - if((long)unix_path <= 0) { - /* We can not translate it, so return the original string */ - return my_passwd; - } + if((long)unix_path <= 0) { + /* We can not translate it, so return the original string */ + return my_passwd; + } - /* If no changes needed just return it */ - if(unix_path == my_passwd->pw_dir) { - return my_passwd; - } + /* If no changes needed just return it */ + if(unix_path == my_passwd->pw_dir) { + return my_passwd; + } - /* Need to copy the structure returned */ - /* Since curl is only using pw_dir, no need to fix up * - /* the pw_shell when running under Bash */ - vms_passwd_cache.pw_name = my_passwd->pw_name; - vms_passwd_cache.pw_uid = my_passwd->pw_uid; - vms_passwd_cache.pw_gid = my_passwd->pw_uid; - vms_passwd_cache.pw_dir = unix_path; - vms_passwd_cache.pw_shell = my_passwd->pw_shell; + /* Need to copy the structure returned */ + /* Since curl is only using pw_dir, no need to fix up */ + /* the pw_shell when running under Bash */ + vms_passwd_cache.pw_name = my_passwd->pw_name; + vms_passwd_cache.pw_uid = my_passwd->pw_uid; + vms_passwd_cache.pw_gid = my_passwd->pw_uid; + vms_passwd_cache.pw_dir = unix_path; + vms_passwd_cache.pw_shell = my_passwd->pw_shell; - return &vms_passwd_cache; + return &vms_passwd_cache; } #ifdef __DECC diff --git a/contrib/curl/lib/share.c b/contrib/curl/lib/share.c index 58c59123..5b3957fc 100644 --- a/contrib/curl/lib/share.c +++ b/contrib/curl/lib/share.c @@ -31,7 +31,7 @@ /* The last #include file should be: */ #include "memdebug.h" -CURLSH * +struct Curl_share * curl_share_init(void) { struct Curl_share *share = calloc(1, sizeof(struct Curl_share)); @@ -49,9 +49,8 @@ curl_share_init(void) #undef curl_share_setopt CURLSHcode -curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) +curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...) { - struct Curl_share *share = (struct Curl_share *)sh; va_list param; int type; curl_lock_function lockfunc; @@ -172,10 +171,8 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) } CURLSHcode -curl_share_cleanup(CURLSH *sh) +curl_share_cleanup(struct Curl_share *share) { - struct Curl_share *share = (struct Curl_share *)sh; - if(share == NULL) return CURLSHE_INVALID; @@ -213,7 +210,7 @@ curl_share_cleanup(CURLSH *sh) CURLSHcode -Curl_share_lock(struct SessionHandle *data, curl_lock_data type, +Curl_share_lock(struct Curl_easy *data, curl_lock_data type, curl_lock_access accesstype) { struct Curl_share *share = data->share; @@ -231,7 +228,7 @@ Curl_share_lock(struct SessionHandle *data, curl_lock_data type, } CURLSHcode -Curl_share_unlock(struct SessionHandle *data, curl_lock_data type) +Curl_share_unlock(struct Curl_easy *data, curl_lock_data type) { struct Curl_share *share = data->share; diff --git a/contrib/curl/lib/share.h b/contrib/curl/lib/share.h index d23d3a04..c039a16c 100644 --- a/contrib/curl/lib/share.h +++ b/contrib/curl/lib/share.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -54,8 +54,8 @@ struct Curl_share { long sessionage; }; -CURLSHcode Curl_share_lock (struct SessionHandle *, curl_lock_data, - curl_lock_access); -CURLSHcode Curl_share_unlock (struct SessionHandle *, curl_lock_data); +CURLSHcode Curl_share_lock(struct Curl_easy *, curl_lock_data, + curl_lock_access); +CURLSHcode Curl_share_unlock(struct Curl_easy *, curl_lock_data); #endif /* HEADER_CURL_SHARE_H */ diff --git a/contrib/curl/lib/sigpipe.h b/contrib/curl/lib/sigpipe.h index 6559c742..800f9d3b 100644 --- a/contrib/curl/lib/sigpipe.h +++ b/contrib/curl/lib/sigpipe.h @@ -38,10 +38,10 @@ struct sigpipe_ignore { * internals, and then sigpipe_restore() will restore the situation when we * return from libcurl again. */ -static void sigpipe_ignore(struct SessionHandle *data, +static void sigpipe_ignore(struct Curl_easy *data, struct sigpipe_ignore *ig) { - /* get a local copy of no_signal because the SessionHandle might not be + /* get a local copy of no_signal because the Curl_easy might not be around when we restore */ ig->no_signal = data->set.no_signal; if(!data->set.no_signal) { diff --git a/contrib/curl/lib/smb.c b/contrib/curl/lib/smb.c index 2c33c117..acf31bc5 100644 --- a/contrib/curl/lib/smb.c +++ b/contrib/curl/lib/smb.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2014, Bill Nagel , Exacq Technologies - * Copyright (C) 2015, Daniel Stenberg, , et al. + * Copyright (C) 2016-2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -23,8 +23,8 @@ #include "curl_setup.h" -#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ - (CURL_SIZEOF_CURL_OFF_T > 4) +#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \ + (CURL_SIZEOF_CURL_OFF_T > 4) #if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO) @@ -32,8 +32,12 @@ #ifdef HAVE_PROCESS_H #include +#ifdef CURL_WINDOWS_APP +#define getpid GetCurrentProcessId +#else #define getpid _getpid #endif +#endif #include "smb.h" #include "urldata.h" @@ -117,18 +121,18 @@ const struct Curl_handler Curl_handler_smbs = { #define SERVICENAME "?????" /* Append a string to an SMB message */ -#define MSGCAT(str) \ - strcpy(p, (str)); \ +#define MSGCAT(str) \ + strcpy(p, (str)); \ p += strlen(str); /* Append a null-terminated string to an SMB message */ -#define MSGCATNULL(str) \ - strcpy(p, (str)); \ +#define MSGCATNULL(str) \ + strcpy(p, (str)); \ p += strlen(str) + 1; /* SMB is mostly little endian */ #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ - defined(__OS400__) + defined(__OS400__) static unsigned short smb_swap16(unsigned short x) { return (unsigned short) ((x << 8) | ((x >> 8) & 0xff)); @@ -137,20 +141,20 @@ static unsigned short smb_swap16(unsigned short x) static unsigned int smb_swap32(unsigned int x) { return (x << 24) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | - ((x >> 24) & 0xff); + ((x >> 24) & 0xff); } #ifdef HAVE_LONGLONG static unsigned long long smb_swap64(unsigned long long x) { return ((unsigned long long) smb_swap32((unsigned int) x) << 32) | - smb_swap32((unsigned int) (x >> 32)); + smb_swap32((unsigned int) (x >> 32)); } #else static unsigned __int64 smb_swap64(unsigned __int64 x) { return ((unsigned __int64) smb_swap32((unsigned int) x) << 32) | - smb_swap32((unsigned int) (x >> 32)); + smb_swap32((unsigned int) (x >> 32)); } #endif #else @@ -197,7 +201,7 @@ static void conn_state(struct connectdata *conn, enum smb_conn_state newstate) if(smb->state != newstate) infof(conn->data, "SMB conn %p state change from %s to %s\n", - (void *)smb, names[smb->state], names[newstate]); + (void *)smb, names[smb->state], names[newstate]); #endif smb->state = newstate; @@ -223,7 +227,7 @@ static void request_state(struct connectdata *conn, if(req->state != newstate) infof(conn->data, "SMB request %p state change from %s to %s\n", - (void *)req, names[req->state], names[newstate]); + (void *)req, names[req->state], names[newstate]); #endif req->state = newstate; @@ -308,8 +312,9 @@ static CURLcode smb_recv_message(struct connectdata *conn, void **msg) if(smbc->got < sizeof(unsigned int)) return CURLE_OK; - nbt_size = Curl_read16_be((unsigned char *)(buf + sizeof(unsigned short))) + - sizeof(unsigned int); + nbt_size = Curl_read16_be((const unsigned char *) + (buf + sizeof(unsigned short))) + + sizeof(unsigned int); if(smbc->got < nbt_size) return CURLE_OK; @@ -320,7 +325,7 @@ static CURLcode smb_recv_message(struct connectdata *conn, void **msg) if(nbt_size >= msg_size + sizeof(unsigned short)) { /* Add the byte count */ msg_size += sizeof(unsigned short) + - Curl_read16_le((unsigned char *)&buf[msg_size]); + Curl_read16_le((const unsigned char *)&buf[msg_size]); if(nbt_size < msg_size) return CURLE_READ_ERROR; } @@ -603,7 +608,7 @@ static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg) /* Check if there is data in the transfer buffer */ if(!smbc->send_size && smbc->upload_size) { int nread = smbc->upload_size > BUFSIZE ? BUFSIZE : - (int) smbc->upload_size; + (int) smbc->upload_size; conn->data->req.upload_fromhere = conn->data->state.uploadbuffer; result = Curl_fillreadbuffer(conn, nread, &nread); if(result && result != CURLE_AGAIN) @@ -673,7 +678,7 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done) switch(smbc->state) { case SMB_NEGOTIATE: - if(h->status) { + if(h->status || smbc->got < sizeof(*nrsp) + sizeof(smbc->challenge) - 1) { connclose(conn, "SMB: negotiation failed"); return CURLE_COULDNT_CONNECT; } @@ -712,6 +717,7 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) { struct smb_request *req = conn->data->req.protop; struct smb_header *h; + struct smb_conn *smbc = &conn->proto.smbc; enum smb_req_state next_state = SMB_DONE; unsigned short len; unsigned short off; @@ -754,7 +760,7 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) break; case SMB_OPEN: - if(h->status) { + if(h->status || smbc->got < sizeof(struct smb_nt_create_response)) { req->result = CURLE_REMOTE_FILE_NOT_FOUND; next_state = SMB_TREE_DISCONNECT; break; @@ -775,17 +781,16 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) break; case SMB_DOWNLOAD: - if(h->status) { + if(h->status || smbc->got < sizeof(struct smb_header) + 14) { req->result = CURLE_RECV_ERROR; next_state = SMB_CLOSE; break; } - len = Curl_read16_le(((unsigned char *) msg) + + len = Curl_read16_le(((const unsigned char *) msg) + sizeof(struct smb_header) + 11); - off = Curl_read16_le(((unsigned char *) msg) + + off = Curl_read16_le(((const unsigned char *) msg) + sizeof(struct smb_header) + 13); if(len > 0) { - struct smb_conn *smbc = &conn->proto.smbc; if(off + sizeof(unsigned int) + len > smbc->got) { failf(conn->data, "Invalid input packet"); result = CURLE_RECV_ERROR; @@ -807,12 +812,12 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done) break; case SMB_UPLOAD: - if(h->status) { + if(h->status || smbc->got < sizeof(struct smb_header) + 6) { req->result = CURLE_UPLOAD_FAILED; next_state = SMB_CLOSE; break; } - len = Curl_read16_le(((unsigned char *) msg) + + len = Curl_read16_le(((const unsigned char *) msg) + sizeof(struct smb_header) + 5); conn->data->req.bytecount += len; conn->data->req.offset += len; @@ -905,7 +910,6 @@ static CURLcode smb_disconnect(struct connectdata *conn, bool dead) /* smb_done is not always called, so cleanup the request */ if(req) { Curl_safefree(req->share); - Curl_safefree(conn->data->req.protop); } return CURLE_OK; @@ -930,7 +934,7 @@ static int smb_getsock(struct connectdata *conn, curl_socket_t *socks, static CURLcode smb_parse_url_path(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct smb_request *req = data->req.protop; char *path; char *slash; diff --git a/contrib/curl/lib/smtp.c b/contrib/curl/lib/smtp.c index 2a5b2bfe..adc346a6 100644 --- a/contrib/curl/lib/smtp.c +++ b/contrib/curl/lib/smtp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -69,16 +69,14 @@ #include "http.h" /* for HTTP proxy tunnel stuff */ #include "socks.h" #include "smtp.h" - #include "strtoofft.h" -#include "strequal.h" +#include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" #include "select.h" #include "multiif.h" #include "url.h" -#include "rawstr.h" #include "curl_gethostname.h" #include "curl_sasl.h" #include "warnless.h" @@ -105,7 +103,7 @@ static CURLcode smtp_parse_custom_request(struct connectdata *conn); static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech, const char *initresp); static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp); -static void smtp_get_message(char *buffer, char** outptr); +static void smtp_get_message(char *buffer, char **outptr); /* * SMTP protocol handler. @@ -128,7 +126,8 @@ const struct Curl_handler Curl_handler_smtp = { ZERO_NULL, /* readwrite */ PORT_SMTP, /* defport */ CURLPROTO_SMTP, /* protocol */ - PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */ + PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */ + PROTOPT_URLOPTIONS }; #ifdef USE_SSL @@ -154,7 +153,7 @@ const struct Curl_handler Curl_handler_smtps = { PORT_SMTPS, /* defport */ CURLPROTO_SMTPS, /* protocol */ PROTOPT_CLOSEACTION | PROTOPT_SSL - | PROTOPT_NOURLQUERY /* flags */ + | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */ }; #endif @@ -280,10 +279,10 @@ static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len, * * Gets the authentication message from the response buffer. */ -static void smtp_get_message(char *buffer, char** outptr) +static void smtp_get_message(char *buffer, char **outptr) { size_t len = 0; - char* message = NULL; + char *message = NULL; /* Find the start of the message */ for(message = buffer + 4; *message == ' ' || *message == '\t'; message++) @@ -520,7 +519,7 @@ static CURLcode smtp_perform_authentication(struct connectdata *conn) static CURLcode smtp_perform_command(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; /* Send the command */ @@ -552,7 +551,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn) char *auth = NULL; char *size = NULL; CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Calculate the FROM parameter */ if(!data->set.str[STRING_MAIL_FROM]) @@ -627,7 +626,7 @@ static CURLcode smtp_perform_mail(struct connectdata *conn) static CURLcode smtp_perform_rcpt_to(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; /* Send the RCPT TO command */ @@ -668,13 +667,13 @@ static CURLcode smtp_state_servergreet_resp(struct connectdata *conn, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(smtpcode/100 != 2) { failf(data, "Got unexpected smtp-server response: %d", smtpcode); - result = CURLE_FTP_WEIRD_SERVER_REPLY; + result = CURLE_WEIRD_SERVER_REPLY; } else result = smtp_perform_ehlo(conn); @@ -688,13 +687,13 @@ static CURLcode smtp_state_starttls_resp(struct connectdata *conn, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ if(smtpcode != 220) { if(data->set.use_ssl != CURLUSESSL_TRY) { - failf(data, "STARTTLS denied. %c", smtpcode); + failf(data, "STARTTLS denied, code %d", smtpcode); result = CURLE_USE_SSL_FAILED; } else @@ -711,7 +710,7 @@ static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct smtp_conn *smtpc = &conn->proto.smtpc; const char *line = data->state.buffer; size_t len = strlen(line); @@ -806,7 +805,7 @@ static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -827,7 +826,7 @@ static CURLcode smtp_state_auth_resp(struct connectdata *conn, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct smtp_conn *smtpc = &conn->proto.smtpc; saslprogress progress; @@ -855,7 +854,7 @@ static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; char *line = data->state.buffer; size_t len = strlen(line); @@ -901,7 +900,7 @@ static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -921,7 +920,7 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; (void)instate; /* no use for this yet */ @@ -953,7 +952,7 @@ static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode, smtpstate instate) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; (void)instate; /* no use for this yet */ @@ -998,7 +997,7 @@ static CURLcode smtp_statemach_act(struct connectdata *conn) { CURLcode result = CURLE_OK; curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int smtpcode; struct smtp_conn *smtpc = &conn->proto.smtpc; struct pingpong *pp = &smtpc->pp; @@ -1108,12 +1107,12 @@ static CURLcode smtp_block_statemach(struct connectdata *conn) return result; } -/* Allocate and initialize the SMTP struct for the current SessionHandle if +/* Allocate and initialize the SMTP struct for the current Curl_easy if required */ static CURLcode smtp_init(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp; smtp = data->req.protop = calloc(sizeof(struct SMTP), 1); @@ -1194,7 +1193,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, bool premature) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; struct pingpong *pp = &conn->proto.smtpc.pp; char *eob; @@ -1284,7 +1283,7 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected, { /* This is SMTP and no proxy */ CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; DEBUGF(infof(conn->data, "DO phase starts\n")); @@ -1423,7 +1422,7 @@ static CURLcode smtp_regular_transfer(struct connectdata *conn, { CURLcode result = CURLE_OK; bool connected = FALSE; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* Make sure size is unknown at this point */ data->req.size = -1; @@ -1446,7 +1445,7 @@ static CURLcode smtp_regular_transfer(struct connectdata *conn, static CURLcode smtp_setup_connection(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result; /* Clear the TLS upgraded flag */ @@ -1512,7 +1511,7 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn) while(*ptr && *ptr != ';') ptr++; - if(strnequal(key, "AUTH=", 5)) + if(strncasecompare(key, "AUTH=", 5)) result = Curl_sasl_parse_url_auth_option(&smtpc->sasl, value, ptr - value); else @@ -1534,7 +1533,7 @@ static CURLcode smtp_parse_url_options(struct connectdata *conn) static CURLcode smtp_parse_url_path(struct connectdata *conn) { /* The SMTP struct is already initialised in smtp_connect() */ - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct smtp_conn *smtpc = &conn->proto.smtpc; const char *path = data->state.path; char localhost[HOSTNAME_MAX + 1]; @@ -1560,7 +1559,7 @@ static CURLcode smtp_parse_url_path(struct connectdata *conn) static CURLcode smtp_parse_custom_request(struct connectdata *conn) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; const char *custom = data->set.str[STRING_CUSTOMREQUEST]; @@ -1581,7 +1580,7 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread) */ ssize_t i; ssize_t si; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SMTP *smtp = data->req.protop; char *scratch = data->state.scratch; char *newscratch = NULL; diff --git a/contrib/curl/lib/smtp.h b/contrib/curl/lib/smtp.h index 6ebec183..b67340a4 100644 --- a/contrib/curl/lib/smtp.h +++ b/contrib/curl/lib/smtp.h @@ -47,9 +47,9 @@ typedef enum { SMTP_LAST /* never used */ } smtpstate; -/* This SMTP struct is used in the SessionHandle. All SMTP data that is +/* This SMTP struct is used in the Curl_easy. All SMTP data that is connection-oriented must be in smtp_conn to properly deal with the fact that - perhaps the SessionHandle is changed between the times the connection is + perhaps the Curl_easy is changed between the times the connection is used. */ struct SMTP { curl_pp_transfer transfer; diff --git a/contrib/curl/lib/socks.c b/contrib/curl/lib/socks.c index 8c412964..774fb20b 100644 --- a/contrib/curl/lib/socks.c +++ b/contrib/curl/lib/socks.c @@ -33,7 +33,6 @@ #include "urldata.h" #include "sendf.h" -#include "strequal.h" #include "select.h" #include "connect.h" #include "timeval.h" @@ -58,7 +57,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */ ssize_t nread; ssize_t allread = 0; int result; - long timeleft; + time_t timeleft; *n = 0; for(;;) { timeleft = Curl_timeleft(conn->data, NULL, TRUE); @@ -67,7 +66,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */ result = CURLE_OPERATION_TIMEDOUT; break; } - if(Curl_socket_ready(sockfd, CURL_SOCKET_BAD, timeleft) <= 0) { + if(SOCKET_READABLE(sockfd, timeleft) <= 0) { result = ~CURLE_OK; break; } @@ -110,16 +109,17 @@ CURLcode Curl_SOCKS4(const char *proxy_name, const char *hostname, int remote_port, int sockindex, - struct connectdata *conn, - bool protocol4a) + struct connectdata *conn) { + const bool protocol4a = + (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE; #define SOCKS4REQLEN 262 unsigned char socksreq[SOCKS4REQLEN]; /* room for SOCKS4 request incl. user id */ int result; CURLcode code; curl_socket_t sock = conn->sock[sockindex]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(Curl_timeleft(data, NULL, TRUE) < 0) { /* time-out, bail out, go home */ @@ -127,6 +127,10 @@ CURLcode Curl_SOCKS4(const char *proxy_name, return CURLE_OPERATION_TIMEDOUT; } + if(conn->bits.httpproxy) + infof(conn->data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n", + protocol4a ? "a" : "", hostname, remote_port); + (void)curlx_nonblock(sock, FALSE); infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port); @@ -170,24 +174,26 @@ CURLcode Curl_SOCKS4(const char *proxy_name, hp=dns->addr; if(hp) { char buf[64]; - unsigned short ip[4]; Curl_printable_address(hp, buf, sizeof(buf)); - if(4 == sscanf(buf, "%hu.%hu.%hu.%hu", - &ip[0], &ip[1], &ip[2], &ip[3])) { - /* Set DSTIP */ - socksreq[4] = (unsigned char)ip[0]; - socksreq[5] = (unsigned char)ip[1]; - socksreq[6] = (unsigned char)ip[2]; - socksreq[7] = (unsigned char)ip[3]; + if(hp->ai_family == AF_INET) { + struct sockaddr_in *saddr_in; + + saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; + socksreq[4] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[0]; + socksreq[5] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[1]; + socksreq[6] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[2]; + socksreq[7] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[3]; + + infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)\n", buf); } - else + else { hp = NULL; /* fail! */ - infof(data, "SOCKS4 connect to %s (locally resolved)\n", buf); + failf(data, "SOCKS4 connection to %s not supported\n", buf); + } Curl_resolv_unlock(data, dns); /* not used anymore from now on */ - } if(!hp) { failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.", @@ -218,7 +224,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, ssize_t written; ssize_t hostnamelen = 0; int packetsize = 9 + - (int)strlen((char*)socksreq + 8); /* size including NUL */ + (int)strlen((char *)socksreq + 8); /* size including NUL */ /* If SOCKS4a, set special invalid IP address 0.0.0.x */ if(protocol4a) { @@ -229,7 +235,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, /* If still enough room in buffer, also append hostname */ hostnamelen = (ssize_t)strlen(hostname) + 1; /* length including NUL */ if(packetsize + hostnamelen <= SOCKS4REQLEN) - strcpy((char*)socksreq + packetsize, hostname); + strcpy((char *)socksreq + packetsize, hostname); else hostnamelen = 0; /* Flag: hostname did not fit in buffer */ } @@ -374,12 +380,17 @@ CURLcode Curl_SOCKS5(const char *proxy_name, int result; CURLcode code; curl_socket_t sock = conn->sock[sockindex]; - struct SessionHandle *data = conn->data; - long timeout; - bool socks5_resolve_local = (conn->proxytype == CURLPROXY_SOCKS5)?TRUE:FALSE; + struct Curl_easy *data = conn->data; + time_t timeout; + bool socks5_resolve_local = + (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE; const size_t hostname_len = strlen(hostname); ssize_t len = 0; + if(conn->bits.httpproxy) + infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n", + hostname, remote_port); + /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ if(!socks5_resolve_local && hostname_len > 255) { infof(conn->data, "SOCKS5: server resolving disabled for hostnames of " @@ -399,7 +410,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, (void)curlx_nonblock(sock, TRUE); /* wait until socket gets connected */ - result = Curl_socket_ready(CURL_SOCKET_BAD, sock, timeout); + result = SOCKET_WRITABLE(sock, timeout); if(-1 == result) { failf(conn->data, "SOCKS5: no connection here"); @@ -429,6 +440,8 @@ CURLcode Curl_SOCKS5(const char *proxy_name, (void)curlx_nonblock(sock, FALSE); + infof(data, "SOCKS5 communication to %s:%d\n", hostname, remote_port); + code = Curl_write_plain(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]), &written); if(code || (written != (2 + (int)socksreq[1]))) { @@ -438,7 +451,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, (void)curlx_nonblock(sock, TRUE); - result = Curl_socket_ready(sock, CURL_SOCKET_BAD, timeout); + result = SOCKET_READABLE(sock, timeout); if(-1 == result) { failf(conn->data, "SOCKS5 nothing to read"); @@ -594,34 +607,41 @@ CURLcode Curl_SOCKS5(const char *proxy_name, if(dns) hp=dns->addr; if(hp) { - struct sockaddr_in *saddr_in; -#ifdef ENABLE_IPV6 - struct sockaddr_in6 *saddr_in6; -#endif int i; + char buf[64]; + Curl_printable_address(hp, buf, sizeof(buf)); if(hp->ai_family == AF_INET) { + struct sockaddr_in *saddr_in; socksreq[len++] = 1; /* ATYP: IPv4 = 1 */ - saddr_in = (struct sockaddr_in*)(void*)hp->ai_addr; + saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr; for(i = 0; i < 4; i++) { - socksreq[len++] = ((unsigned char*)&saddr_in->sin_addr.s_addr)[i]; - infof(data, "%d\n", socksreq[len-1]); + socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i]; } + + infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)\n", buf); } #ifdef ENABLE_IPV6 else if(hp->ai_family == AF_INET6) { + struct sockaddr_in6 *saddr_in6; socksreq[len++] = 4; /* ATYP: IPv6 = 4 */ - saddr_in6 = (struct sockaddr_in6*)(void*)hp->ai_addr; + saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr; for(i = 0; i < 16; i++) { - socksreq[len++] = ((unsigned char*)&saddr_in6->sin6_addr.s6_addr)[i]; + socksreq[len++] = + ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i]; } + + infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)\n", buf); } #endif - else + else { hp = NULL; /* fail! */ + failf(data, "SOCKS5 connection to %s not supported\n", buf); + } + Curl_resolv_unlock(data, dns); /* not used anymore from now on */ } if(!hp) { @@ -668,39 +688,6 @@ CURLcode Curl_SOCKS5(const char *proxy_name, "SOCKS5 reply has wrong version, version should be 5."); return CURLE_COULDNT_CONNECT; } - if(socksreq[1] != 0) { /* Anything besides 0 is an error */ - if(socksreq[3] == 1) { - failf(data, - "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), - (unsigned char)socksreq[1]); - } - else if(socksreq[3] == 3) { - failf(data, - "Can't complete SOCKS5 connection to %s:%d. (%d)", - hostname, - (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), - (unsigned char)socksreq[1]); - } - else if(socksreq[3] == 4) { - failf(data, - "Can't complete SOCKS5 connection to %02x%02x:%02x%02x:" - "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%d. (%d)", - (unsigned char)socksreq[4], (unsigned char)socksreq[5], - (unsigned char)socksreq[6], (unsigned char)socksreq[7], - (unsigned char)socksreq[8], (unsigned char)socksreq[9], - (unsigned char)socksreq[10], (unsigned char)socksreq[11], - (unsigned char)socksreq[12], (unsigned char)socksreq[13], - (unsigned char)socksreq[14], (unsigned char)socksreq[15], - (unsigned char)socksreq[16], (unsigned char)socksreq[17], - (unsigned char)socksreq[18], (unsigned char)socksreq[19], - (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]), - (unsigned char)socksreq[1]); - } - return CURLE_COULDNT_CONNECT; - } /* Fix: in general, returned BND.ADDR is variable length parameter by RFC 1928, so the reply packet should be read until the end to avoid errors at @@ -735,10 +722,9 @@ CURLcode Curl_SOCKS5(const char *proxy_name, /* decrypt_gssapi_blockread already read the whole packet */ #endif if(len > 10) { - len -= 10; result = Curl_blockread_all(conn, sock, (char *)&socksreq[10], - len, &actualread); - if(result || (len != actualread)) { + len - 10, &actualread); + if(result || ((len - 10) != actualread)) { failf(data, "Failed to receive SOCKS5 connect request ack."); return CURLE_COULDNT_CONNECT; } @@ -747,6 +733,49 @@ CURLcode Curl_SOCKS5(const char *proxy_name, } #endif + if(socksreq[1] != 0) { /* Anything besides 0 is an error */ + if(socksreq[3] == 1) { + failf(data, + "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (((unsigned char)socksreq[8] << 8) | + (unsigned char)socksreq[9]), + (unsigned char)socksreq[1]); + } + else if(socksreq[3] == 3) { + unsigned char port_upper = (unsigned char)socksreq[len - 2]; + socksreq[len - 2] = 0; + failf(data, + "Can't complete SOCKS5 connection to %s:%d. (%d)", + (char *)&socksreq[5], + ((port_upper << 8) | + (unsigned char)socksreq[len - 1]), + (unsigned char)socksreq[1]); + socksreq[len - 2] = port_upper; + } + else if(socksreq[3] == 4) { + failf(data, + "Can't complete SOCKS5 connection to %02x%02x:%02x%02x:" + "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%d. (%d)", + (unsigned char)socksreq[4], (unsigned char)socksreq[5], + (unsigned char)socksreq[6], (unsigned char)socksreq[7], + (unsigned char)socksreq[8], (unsigned char)socksreq[9], + (unsigned char)socksreq[10], (unsigned char)socksreq[11], + (unsigned char)socksreq[12], (unsigned char)socksreq[13], + (unsigned char)socksreq[14], (unsigned char)socksreq[15], + (unsigned char)socksreq[16], (unsigned char)socksreq[17], + (unsigned char)socksreq[18], (unsigned char)socksreq[19], + (((unsigned char)socksreq[20] << 8) | + (unsigned char)socksreq[21]), + (unsigned char)socksreq[1]); + } + return CURLE_COULDNT_CONNECT; + } + else { + infof(data, "SOCKS5 request granted.\n"); + } + (void)curlx_nonblock(sock, TRUE); return CURLE_OK; /* Proxy was successful! */ } diff --git a/contrib/curl/lib/socks.h b/contrib/curl/lib/socks.h index a44ada6b..348707e7 100644 --- a/contrib/curl/lib/socks.h +++ b/contrib/curl/lib/socks.h @@ -25,7 +25,7 @@ #include "curl_setup.h" #ifdef CURL_DISABLE_PROXY -#define Curl_SOCKS4(a,b,c,d,e,f) CURLE_NOT_BUILT_IN +#define Curl_SOCKS4(a,b,c,d,e) CURLE_NOT_BUILT_IN #define Curl_SOCKS5(a,b,c,d,e,f) CURLE_NOT_BUILT_IN #else /* @@ -49,8 +49,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, const char *hostname, int remote_port, int sockindex, - struct connectdata *conn, - bool protocol4a); + struct connectdata *conn); /* * This function logs in to a SOCKS5 proxy and sends the specifics to the diff --git a/contrib/curl/lib/socks_gssapi.c b/contrib/curl/lib/socks_gssapi.c index 1214048b..54d06350 100644 --- a/contrib/curl/lib/socks_gssapi.c +++ b/contrib/curl/lib/socks_gssapi.c @@ -43,10 +43,10 @@ static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT; /* * Helper GSS-API error functions. */ -static int check_gss_err(struct SessionHandle *data, +static int check_gss_err(struct Curl_easy *data, OM_uint32 major_status, OM_uint32 minor_status, - const char* function) + const char *function) { if(GSS_ERROR(major_status)) { OM_uint32 maj_stat, min_stat; @@ -65,7 +65,7 @@ static int check_gss_err(struct SessionHandle *data, &msg_ctx, &status_string); if(maj_stat == GSS_S_COMPLETE) { if(sizeof(buf) > len + status_string.length + 1) { - strcpy(buf+len, (char*) status_string.value); + strcpy(buf+len, (char *) status_string.value); len += status_string.length; } gss_release_buffer(&min_stat, &status_string); @@ -86,7 +86,7 @@ static int check_gss_err(struct SessionHandle *data, &msg_ctx, &status_string); if(maj_stat == GSS_S_COMPLETE) { if(sizeof(buf) > len + status_string.length) - strcpy(buf+len, (char*) status_string.value); + strcpy(buf+len, (char *) status_string.value); gss_release_buffer(&min_stat, &status_string); break; } @@ -102,7 +102,7 @@ static int check_gss_err(struct SessionHandle *data, CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_socket_t sock = conn->sock[sockindex]; CURLcode code; ssize_t actualread; @@ -123,6 +123,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, unsigned char socksreq[4]; /* room for GSS-API exchange header only */ const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; + const size_t serviceptr_length = strlen(serviceptr); /* GSS-API request looks like * +----+------+-----+----------------+ @@ -134,22 +135,23 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, /* prepare service name */ if(strchr(serviceptr, '/')) { - service.value = malloc(strlen(serviceptr)); + service.length = serviceptr_length; + service.value = malloc(service.length); if(!service.value) return CURLE_OUT_OF_MEMORY; - service.length = strlen(serviceptr); memcpy(service.value, serviceptr, service.length); gss_major_status = gss_import_name(&gss_minor_status, &service, (gss_OID) GSS_C_NULL_OID, &server); } else { - service.value = malloc(strlen(serviceptr) +strlen(conn->proxy.name)+2); + service.value = malloc(serviceptr_length + + strlen(conn->socks_proxy.host.name)+2); if(!service.value) return CURLE_OUT_OF_MEMORY; - service.length = strlen(serviceptr) +strlen(conn->proxy.name)+1; + service.length = serviceptr_length + strlen(conn->socks_proxy.host.name)+1; snprintf(service.value, service.length+1, "%s@%s", - serviceptr, conn->proxy.name); + serviceptr, conn->socks_proxy.host.name); gss_major_status = gss_import_name(&gss_minor_status, &service, GSS_C_NT_HOSTBASED_SERVICE, &server); @@ -290,9 +292,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_release_name(&gss_status, &server); /* Everything is good so far, user was authenticated! */ - gss_major_status = gss_inquire_context (&gss_minor_status, gss_context, - &gss_client_name, NULL, NULL, NULL, - NULL, NULL, NULL); + gss_major_status = gss_inquire_context(&gss_minor_status, gss_context, + &gss_client_name, NULL, NULL, NULL, + NULL, NULL, NULL); if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_inquire_context")) { gss_delete_sec_context(&gss_status, &gss_context, NULL); diff --git a/contrib/curl/lib/socks_sspi.c b/contrib/curl/lib/socks_sspi.c index ec564b48..edc73ad2 100644 --- a/contrib/curl/lib/socks_sspi.c +++ b/contrib/curl/lib/socks_sspi.c @@ -34,6 +34,7 @@ #include "curl_sspi.h" #include "curl_multibyte.h" #include "warnless.h" +#include "strdup.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" #include "curl_memory.h" @@ -44,7 +45,7 @@ */ static int check_sspi_err(struct connectdata *conn, SECURITY_STATUS status, - const char* function) + const char *function) { if(status != SEC_E_OK && status != SEC_I_COMPLETE_AND_CONTINUE && @@ -61,7 +62,7 @@ static int check_sspi_err(struct connectdata *conn, CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_socket_t sock = conn->sock[sockindex]; CURLcode code; ssize_t actualread; @@ -85,6 +86,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, unsigned char socksreq[4]; /* room for GSS-API exchange header only */ const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; + const size_t service_length = strlen(service); /* GSS-API request looks like * +----+------+-----+----------------+ @@ -96,17 +98,18 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, /* prepare service name */ if(strchr(service, '/')) { - service_name = malloc(strlen(service)); + service_name = strdup(service); if(!service_name) return CURLE_OUT_OF_MEMORY; - memcpy(service_name, service, strlen(service)); } else { - service_name = malloc(strlen(service) + strlen(conn->proxy.name) + 2); + service_name = malloc(service_length + + strlen(conn->socks_proxy.host.name) + 2); if(!service_name) return CURLE_OUT_OF_MEMORY; - snprintf(service_name, strlen(service) +strlen(conn->proxy.name)+2, - "%s/%s", service, conn->proxy.name); + snprintf(service_name, service_length + + strlen(conn->socks_proxy.host.name)+2, "%s/%s", + service, conn->socks_proxy.host.name); } input_desc.cBuffers = 1; diff --git a/contrib/curl/lib/speedcheck.c b/contrib/curl/lib/speedcheck.c index 4706d2df..bc15d97b 100644 --- a/contrib/curl/lib/speedcheck.c +++ b/contrib/curl/lib/speedcheck.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -28,20 +28,20 @@ #include "multiif.h" #include "speedcheck.h" -void Curl_speedinit(struct SessionHandle *data) +void Curl_speedinit(struct Curl_easy *data) { memset(&data->state.keeps_speed, 0, sizeof(struct timeval)); } -CURLcode Curl_speedcheck(struct SessionHandle *data, +CURLcode Curl_speedcheck(struct Curl_easy *data, struct timeval now) { if((data->progress.current_speed >= 0) && data->set.low_speed_time && (Curl_tvlong(data->state.keeps_speed) != 0) && (data->progress.current_speed < data->set.low_speed_limit)) { - long howlong = Curl_tvdiff(now, data->state.keeps_speed); - long nextcheck = (data->set.low_speed_time * 1000) - howlong; + time_t howlong = Curl_tvdiff(now, data->state.keeps_speed); + time_t nextcheck = (data->set.low_speed_time * 1000) - howlong; /* We are now below the "low speed limit". If we are below it for "low speed time" seconds we consider that enough reason diff --git a/contrib/curl/lib/speedcheck.h b/contrib/curl/lib/speedcheck.h index e1921d66..7dbe3d6d 100644 --- a/contrib/curl/lib/speedcheck.h +++ b/contrib/curl/lib/speedcheck.h @@ -26,8 +26,8 @@ #include "timeval.h" -void Curl_speedinit(struct SessionHandle *data); -CURLcode Curl_speedcheck(struct SessionHandle *data, +void Curl_speedinit(struct Curl_easy *data); +CURLcode Curl_speedcheck(struct Curl_easy *data, struct timeval now); #endif /* HEADER_CURL_SPEEDCHECK_H */ diff --git a/contrib/curl/lib/ssh.c b/contrib/curl/lib/ssh.c index d5a1a2a8..086d40ec 100644 --- a/contrib/curl/lib/ssh.c +++ b/contrib/curl/lib/ssh.c @@ -71,8 +71,8 @@ #include "url.h" #include "speedcheck.h" #include "getinfo.h" - -#include "strequal.h" +#include "strdup.h" +#include "strcase.h" #include "vtls/vtls.h" #include "connect.h" #include "strerror.h" @@ -239,7 +239,7 @@ kbd_callback(const char *name, int name_len, const char *instruction, static CURLcode sftp_libssh2_error_to_CURLE(int err) { - switch (err) { + switch(err) { case LIBSSH2_FX_OK: return CURLE_OK; @@ -271,7 +271,7 @@ static CURLcode sftp_libssh2_error_to_CURLE(int err) static CURLcode libssh2_session_error_to_CURLE(int err) { - switch (err) { + switch(err) { /* Ordered by order of appearance in libssh2.h */ case LIBSSH2_ERROR_NONE: return CURLE_OK; @@ -413,15 +413,15 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn, char **path) /* returns the allocated real path to work with */ { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; char *real_path = NULL; char *working_path; - int working_path_len; - - working_path = curl_easy_unescape(data, data->state.path, 0, - &working_path_len); - if(!working_path) - return CURLE_OUT_OF_MEMORY; + size_t working_path_len; + CURLcode result = + Curl_urldecode(data, data->state.path, 0, &working_path, + &working_path_len, FALSE); + if(result) + return result; /* Check for /~/, indicating relative to the user's home directory */ if(conn->handler->protocol & CURLPROTO_SCP) { @@ -473,7 +473,7 @@ static CURLcode ssh_getworkingpath(struct connectdata *conn, } #ifdef HAVE_LIBSSH2_KNOWNHOST_API -static int sshkeycallback(CURL *easy, +static int sshkeycallback(struct Curl_easy *easy, const struct curl_khkey *knownkey, /* known */ const struct curl_khkey *foundkey, /* found */ enum curl_khmatch match, @@ -522,7 +522,7 @@ static CURLcode ssh_knownhost(struct connectdata *conn) CURLcode result = CURLE_OK; #ifdef HAVE_LIBSSH2_KNOWNHOST_API - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; if(data->set.str[STRING_SSH_KNOWNHOSTS]) { /* we're asked to verify the host against a file */ @@ -657,7 +657,7 @@ static CURLcode ssh_knownhost(struct connectdata *conn) static CURLcode ssh_check_fingerprint(struct connectdata *conn) { struct ssh_conn *sshc = &conn->proto.sshc; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]; char md5buffer[33]; int i; @@ -676,7 +676,7 @@ static CURLcode ssh_check_fingerprint(struct connectdata *conn) * against a known fingerprint, if available. */ if(pubkey_md5 && strlen(pubkey_md5) == 32) { - if(!fingerprint || !strequal(md5buffer, pubkey_md5)) { + if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) { if(fingerprint) failf(data, "Denied establishing ssh session: mismatch md5 fingerprint. " @@ -708,7 +708,7 @@ static CURLcode ssh_check_fingerprint(struct connectdata *conn) static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct SSHPROTO *sftp_scp = data->req.protop; struct ssh_conn *sshc = &conn->proto.sshc; curl_socket_t sock = conn->sock[FIRSTSOCKET]; @@ -782,14 +782,14 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_AUTH_DONE); break; } - else if((err = libssh2_session_last_errno(sshc->ssh_session)) == - LIBSSH2_ERROR_EAGAIN) { - rc = LIBSSH2_ERROR_EAGAIN; - break; - } else { - state(conn, SSH_SESSION_FREE); - sshc->actualcode = libssh2_session_error_to_CURLE(err); + err = libssh2_session_last_errno(sshc->ssh_session); + if(err == LIBSSH2_ERROR_EAGAIN) + rc = LIBSSH2_ERROR_EAGAIN; + else { + state(conn, SSH_SESSION_FREE); + sshc->actualcode = libssh2_session_error_to_CURLE(err); + } break; } } @@ -874,7 +874,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } - sshc->passphrase = data->set.str[STRING_KEY_PASSWD]; + sshc->passphrase = data->set.ssl.key_passwd; if(!sshc->passphrase) sshc->passphrase = ""; @@ -918,6 +918,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) &err_msg, NULL, 0); infof(data, "SSH public key authentication failed: %s\n", err_msg); state(conn, SSH_AUTH_PASS_INIT); + rc = 0; /* clear rc and continue */ } break; @@ -928,6 +929,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } else { state(conn, SSH_AUTH_HOST_INIT); + rc = 0; /* clear rc and continue */ } break; @@ -989,6 +991,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc < 0) { infof(data, "Failure connecting to agent\n"); state(conn, SSH_AUTH_KEY_INIT); + rc = 0; /* clear rc and continue */ } else { state(conn, SSH_AUTH_AGENT_LIST); @@ -1008,6 +1011,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) if(rc < 0) { infof(data, "Failure requesting identities to agent\n"); state(conn, SSH_AUTH_KEY_INIT); + rc = 0; /* clear rc and continue */ } else { state(conn, SSH_AUTH_AGENT); @@ -1161,8 +1165,13 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) else { /* Return the error type */ err = sftp_libssh2_last_error(sshc->sftp_session); - result = sftp_libssh2_error_to_CURLE(err); - sshc->actualcode = result?result:CURLE_SSH; + if(err) + result = sftp_libssh2_error_to_CURLE(err); + else + /* in this case, the error wasn't in the SFTP level but for example + a time-out or similar */ + result = CURLE_SSH; + sshc->actualcode = result; DEBUGF(infof(data, "error = %d makes libcurl = %d\n", err, (int)result)); state(conn, SSH_STOP); @@ -1228,7 +1237,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->acceptfail = TRUE; } - if(curl_strequal("pwd", cmd)) { + if(strcasecompare("pwd", cmd)) { /* output debug output if that is requested */ char *tmp = aprintf("257 \"%s\" is current directory.\n", sftp_scp->path); @@ -1292,9 +1301,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) * OpenSSH's sftp program and call the appropriate libssh2 * functions. */ - if(curl_strnequal(cmd, "chgrp ", 6) || - curl_strnequal(cmd, "chmod ", 6) || - curl_strnequal(cmd, "chown ", 6) ) { + if(strncasecompare(cmd, "chgrp ", 6) || + strncasecompare(cmd, "chmod ", 6) || + strncasecompare(cmd, "chown ", 6) ) { /* attribute change */ /* sshc->quote_path1 contains the mode to set */ @@ -1316,8 +1325,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_QUOTE_STAT); break; } - else if(curl_strnequal(cmd, "ln ", 3) || - curl_strnequal(cmd, "symlink ", 8)) { + else if(strncasecompare(cmd, "ln ", 3) || + strncasecompare(cmd, "symlink ", 8)) { /* symbolic linking */ /* sshc->quote_path1 is the source */ /* get the destination */ @@ -1337,12 +1346,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_QUOTE_SYMLINK); break; } - else if(curl_strnequal(cmd, "mkdir ", 6)) { + else if(strncasecompare(cmd, "mkdir ", 6)) { /* create dir */ state(conn, SSH_SFTP_QUOTE_MKDIR); break; } - else if(curl_strnequal(cmd, "rename ", 7)) { + else if(strncasecompare(cmd, "rename ", 7)) { /* rename file */ /* first param is the source path */ /* second param is the dest. path */ @@ -1361,17 +1370,17 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) state(conn, SSH_SFTP_QUOTE_RENAME); break; } - else if(curl_strnequal(cmd, "rmdir ", 6)) { + else if(strncasecompare(cmd, "rmdir ", 6)) { /* delete dir */ state(conn, SSH_SFTP_QUOTE_RMDIR); break; } - else if(curl_strnequal(cmd, "rm ", 3)) { + else if(strncasecompare(cmd, "rm ", 3)) { state(conn, SSH_SFTP_QUOTE_UNLINK); break; } #ifdef HAS_STATVFS_SUPPORT - else if(curl_strnequal(cmd, "statvfs ", 8)) { + else if(strncasecompare(cmd, "statvfs ", 8)) { state(conn, SSH_SFTP_QUOTE_STATVFS); break; } @@ -1426,7 +1435,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->acceptfail = TRUE; } - if(!curl_strnequal(cmd, "chmod", 5)) { + if(!strncasecompare(cmd, "chmod", 5)) { /* Since chown and chgrp only set owner OR group but libssh2 wants to * set them both at once, we need to obtain the current ownership * first. This takes an extra protocol round trip. @@ -1452,7 +1461,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } /* Now set the new attributes... */ - if(curl_strnequal(cmd, "chgrp", 5)) { + if(strncasecompare(cmd, "chgrp", 5)) { sshc->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10); sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) && @@ -1466,7 +1475,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } } - else if(curl_strnequal(cmd, "chmod", 5)) { + else if(strncasecompare(cmd, "chmod", 5)) { sshc->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8); sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS; /* permissions are octal */ @@ -1481,7 +1490,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } } - else if(curl_strnequal(cmd, "chown", 5)) { + else if(strncasecompare(cmd, "chown", 5)) { sshc->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10); sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID; if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) && @@ -1795,6 +1804,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) (data->set.ftp_create_missing_dirs && (strlen(sftp_scp->path) > 1))) { /* try to create the path remotely */ + rc = 0; /* clear rc and continue */ sshc->secondCreateDirs = 1; state(conn, SSH_SFTP_CREATE_DIRS_INIT); break; @@ -1890,7 +1900,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) /* since we don't really wait for anything at this point, we want the state machine to move on as soon as possible so we set a very short timeout here */ - Curl_expire(data, 1); + Curl_expire(data, 0); state(conn, SSH_STOP); } @@ -1931,7 +1941,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } *sshc->slash_pos = '/'; ++sshc->slash_pos; - if(rc == -1) { + if(rc < 0) { /* * Abort if failure wasn't that the dir already exists or the * permission was denied (creation might succeed further down the @@ -1946,6 +1956,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->actualcode = result?result:CURLE_SSH; break; } + else { + rc = 0; /* clear rc and continue */ + } } state(conn, SSH_SFTP_CREATE_DIRS); break; @@ -1982,12 +1995,14 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) break; } } - if((sshc->readdir_filename = malloc(PATH_MAX+1)) == NULL) { + sshc->readdir_filename = malloc(PATH_MAX+1); + if(!sshc->readdir_filename) { state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } - if((sshc->readdir_longentry = malloc(PATH_MAX+1)) == NULL) { + sshc->readdir_longentry = malloc(PATH_MAX+1); + if(!sshc->readdir_longentry) { Curl_safefree(sshc->readdir_filename); state(conn, SSH_SFTP_CLOSE); sshc->actualcode = CURLE_OUT_OF_MEMORY; @@ -2107,9 +2122,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) /* get room for the filename and extra output */ sshc->readdir_totalLen += 4 + sshc->readdir_len; - new_readdir_line = realloc(sshc->readdir_line, sshc->readdir_totalLen); + new_readdir_line = Curl_saferealloc(sshc->readdir_line, + sshc->readdir_totalLen); if(!new_readdir_line) { - Curl_safefree(sshc->readdir_line); + sshc->readdir_line = NULL; Curl_safefree(sshc->readdir_filename); Curl_safefree(sshc->readdir_longentry); state(conn, SSH_SFTP_CLOSE); @@ -2646,7 +2662,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) else if(rc < 0) { infof(data, "Failed to disconnect from libssh2 agent\n"); } - libssh2_agent_free (sshc->ssh_agent); + libssh2_agent_free(sshc->ssh_agent); sshc->ssh_agent = NULL; /* NB: there is no need to free identities, they are part of internal @@ -2783,13 +2799,16 @@ static int ssh_getsock(struct connectdata *conn, static void ssh_block2waitfor(struct connectdata *conn, bool block) { struct ssh_conn *sshc = &conn->proto.sshc; - int dir; - if(block && (dir = libssh2_session_block_directions(sshc->ssh_session))) { - /* translate the libssh2 define bits into our own bit defines */ - conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) | - ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND)?KEEP_SEND:0); + int dir = 0; + if(block) { + dir = libssh2_session_block_directions(sshc->ssh_session); + if(dir) { + /* translate the libssh2 define bits into our own bit defines */ + conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) | + ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND)?KEEP_SEND:0); + } } - else + if(!dir) /* It didn't block or libssh2 didn't reveal in which direction, put back the original set */ conn->waitfor = sshc->orig_waitfor; @@ -2819,7 +2838,7 @@ static CURLcode ssh_block_statemach(struct connectdata *conn, { struct ssh_conn *sshc = &conn->proto.sshc; CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; while((sshc->state != SSH_STOP) && !result) { bool block; @@ -2855,8 +2874,8 @@ static CURLcode ssh_block_statemach(struct connectdata *conn, if(LIBSSH2_SESSION_BLOCK_OUTBOUND & dir) fd_write = sock; /* wait for the socket to become ready */ - Curl_socket_ready(fd_read, fd_write, - left>1000?1000:left); /* ignore result */ + (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, + left>1000?1000:left); /* ignore result */ } #endif @@ -2893,7 +2912,7 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done) #endif struct ssh_conn *ssh; CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* initialize per-handle data if not already */ if(!data->req.protop) @@ -3019,7 +3038,7 @@ static CURLcode ssh_do(struct connectdata *conn, bool *done) { CURLcode result; bool connected = 0; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssh_conn *sshc = &conn->proto.sshc; *done = FALSE; /* default to false */ @@ -3052,8 +3071,6 @@ static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection) struct ssh_conn *ssh = &conn->proto.sshc; (void) dead_connection; - Curl_safefree(conn->data->req.protop); - if(ssh->ssh_session) { /* only if there's a session still around to use! */ @@ -3106,7 +3123,6 @@ static CURLcode scp_done(struct connectdata *conn, CURLcode status, } -/* return number of received (decrypted) bytes */ static ssize_t scp_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *err) { @@ -3131,10 +3147,6 @@ static ssize_t scp_send(struct connectdata *conn, int sockindex, return nwrite; } -/* - * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return - * a regular CURLcode value. - */ static ssize_t scp_recv(struct connectdata *conn, int sockindex, char *mem, size_t len, CURLcode *err) { @@ -3215,8 +3227,6 @@ static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection) DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n")); - Curl_safefree(conn->data->req.protop); - if(conn->proto.sshc.ssh_session) { /* only if there's a session still around to use! */ state(conn, SSH_SFTP_SHUTDOWN); @@ -3387,7 +3397,7 @@ get_pathname(const char **cpp, char **path) static const char *sftp_libssh2_strerror(int err) { - switch (err) { + switch(err) { case LIBSSH2_FX_NO_SUCH_FILE: return "No such file or directory"; diff --git a/contrib/curl/lib/ssh.h b/contrib/curl/lib/ssh.h index 5b4b78ff..b350dcf3 100644 --- a/contrib/curl/lib/ssh.h +++ b/contrib/curl/lib/ssh.h @@ -98,7 +98,7 @@ typedef enum { } sshstate; /* this struct is used in the HandleData struct which is part of the - SessionHandle, which means this is used on a per-easy handle basis. + Curl_easy, which means this is used on a per-easy handle basis. Everything that is strictly related to a connection is banned from this struct. */ struct SSHPROTO { diff --git a/contrib/curl/lib/rawstr.c b/contrib/curl/lib/strcase.c similarity index 80% rename from contrib/curl/lib/rawstr.c rename to contrib/curl/lib/strcase.c index 5665ebd3..a750f7b4 100644 --- a/contrib/curl/lib/rawstr.c +++ b/contrib/curl/lib/strcase.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,7 +22,9 @@ #include "curl_setup.h" -#include "rawstr.h" +#include + +#include "strcase.h" /* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because its behavior is altered by the current locale. */ @@ -32,7 +34,7 @@ char Curl_raw_toupper(char in) if(in >= 'a' && in <= 'z') return (char)('A' + in - 'a'); #else - switch (in) { + switch(in) { case 'a': return 'A'; case 'b': @@ -99,9 +101,11 @@ char Curl_raw_toupper(char in) * * The function is capable of comparing a-z case insensitively even for * non-ascii. + * + * @unittest: 1301 */ -int Curl_raw_equal(const char *first, const char *second) +int Curl_strcasecompare(const char *first, const char *second) { while(*first && *second) { if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) @@ -116,7 +120,20 @@ int Curl_raw_equal(const char *first, const char *second) return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second)); } -int Curl_raw_nequal(const char *first, const char *second, size_t max) +int Curl_safe_strcasecompare(const char *first, const char *second) +{ + if(first && second) + /* both pointers point to something then compare them */ + return Curl_strcasecompare(first, second); + else + /* if both pointers are NULL then treat them as equal */ + return (NULL == first && NULL == second); +} + +/* + * @unittest: 1301 + */ +int Curl_strncasecompare(const char *first, const char *second, size_t max) { while(*first && *second && max) { if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) { @@ -146,3 +163,14 @@ void Curl_strntoupper(char *dest, const char *src, size_t n) *dest++ = Curl_raw_toupper(*src); } while(*src++ && --n); } + +/* --- public functions --- */ + +int curl_strequal(const char *first, const char *second) +{ + return Curl_strcasecompare(first, second); +} +int curl_strnequal(const char *first, const char *second, size_t max) +{ + return Curl_strncasecompare(first, second, max); +} diff --git a/contrib/curl/lib/rawstr.h b/contrib/curl/lib/strcase.h similarity index 64% rename from contrib/curl/lib/rawstr.h rename to contrib/curl/lib/strcase.h index 4af00f14..ea2abc8b 100644 --- a/contrib/curl/lib/rawstr.h +++ b/contrib/curl/lib/strcase.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_RAWSTR_H -#define HEADER_CURL_RAWSTR_H +#ifndef HEADER_CURL_STRCASE_H +#define HEADER_CURL_STRCASE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -25,23 +25,27 @@ #include /* - * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant - * to be locale independent and only compare strings we know are safe for - * this. + * Only "raw" case insensitive strings. This is meant to be locale independent + * and only compare strings we know are safe for this. * * The function is capable of comparing a-z case insensitively even for * non-ascii. */ -int Curl_raw_equal(const char *first, const char *second); -int Curl_raw_nequal(const char *first, const char *second, size_t max); + +#define strcasecompare(a,b) Curl_strcasecompare(a,b) +#define strncasecompare(a,b,c) Curl_strncasecompare(a,b,c) + +int Curl_strcasecompare(const char *first, const char *second); +int Curl_safe_strcasecompare(const char *first, const char *second); +int Curl_strncasecompare(const char *first, const char *second, size_t max); char Curl_raw_toupper(char in); /* checkprefix() is a shorter version of the above, used when the first argument is zero-byte terminated */ -#define checkprefix(a,b) Curl_raw_nequal(a,b,strlen(a)) +#define checkprefix(a,b) curl_strnequal(a,b,strlen(a)) void Curl_strntoupper(char *dest, const char *src, size_t n); +char Curl_raw_toupper(char in); -#endif /* HEADER_CURL_RAWSTR_H */ - +#endif /* HEADER_CURL_STRCASE_H */ diff --git a/contrib/curl/lib/strdup.c b/contrib/curl/lib/strdup.c index 23f554e5..136b6937 100644 --- a/contrib/curl/lib/strdup.c +++ b/contrib/curl/lib/strdup.c @@ -65,9 +65,9 @@ char *curlx_strdup(const char *str) * Returns the new pointer or NULL on failure. * ***************************************************************************/ -char *Curl_memdup(const char *src, size_t length) +void *Curl_memdup(const void *src, size_t length) { - char *buffer = malloc(length); + void *buffer = malloc(length); if(!buffer) return NULL; /* fail */ @@ -75,3 +75,26 @@ char *Curl_memdup(const char *src, size_t length) return buffer; } + +/*************************************************************************** + * + * Curl_saferealloc(ptr, size) + * + * Does a normal realloc(), but will free the data pointer if the realloc + * fails. If 'size' is zero, it will free the data and return a failure. + * + * This convenience function is provided and used to help us avoid a common + * mistake pattern when we could pass in a zero, catch the NULL return and end + * up free'ing the memory twice. + * + * Returns the new pointer or NULL on failure. + * + ***************************************************************************/ +void *Curl_saferealloc(void *ptr, size_t size) +{ + void *datap = realloc(ptr, size); + if(size && !datap) + /* only free 'ptr' if size was non-zero */ + free(ptr); + return datap; +} diff --git a/contrib/curl/lib/strdup.h b/contrib/curl/lib/strdup.h index 4c48ca41..ae3d5d01 100644 --- a/contrib/curl/lib/strdup.h +++ b/contrib/curl/lib/strdup.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,6 +26,7 @@ #ifndef HAVE_STRDUP extern char *curlx_strdup(const char *str); #endif -char *Curl_memdup(const char *src, size_t buffer_length); +void *Curl_memdup(const void *src, size_t buffer_length); +void *Curl_saferealloc(void *ptr, size_t size); #endif /* HEADER_CURL_STRDUP_H */ diff --git a/contrib/curl/lib/strequal.c b/contrib/curl/lib/strequal.c deleted file mode 100644 index 01c37844..00000000 --- a/contrib/curl/lib/strequal.c +++ /dev/null @@ -1,79 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2013, Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.haxx.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - ***************************************************************************/ - -#include "curl_setup.h" - -#ifdef HAVE_STRINGS_H -#include -#endif - -#include "strequal.h" - -/* - * @unittest: 1301 - */ -int curl_strequal(const char *first, const char *second) -{ -#if defined(HAVE_STRCASECMP) - return !(strcasecmp)(first, second); -#elif defined(HAVE_STRCMPI) - return !(strcmpi)(first, second); -#elif defined(HAVE_STRICMP) - return !(stricmp)(first, second); -#else - while(*first && *second) { - if(toupper(*first) != toupper(*second)) { - break; - } - first++; - second++; - } - return toupper(*first) == toupper(*second); -#endif -} - -/* - * @unittest: 1301 - */ -int curl_strnequal(const char *first, const char *second, size_t max) -{ -#if defined(HAVE_STRNCASECMP) - return !strncasecmp(first, second, max); -#elif defined(HAVE_STRNCMPI) - return !strncmpi(first, second, max); -#elif defined(HAVE_STRNICMP) - return !strnicmp(first, second, max); -#else - while(*first && *second && max) { - if(toupper(*first) != toupper(*second)) { - break; - } - max--; - first++; - second++; - } - if(0 == max) - return 1; /* they are equal this far */ - - return toupper(*first) == toupper(*second); -#endif -} diff --git a/contrib/curl/lib/strerror.c b/contrib/curl/lib/strerror.c index 0e268d5e..7e5cde47 100644 --- a/contrib/curl/lib/strerror.c +++ b/contrib/curl/lib/strerror.c @@ -35,8 +35,8 @@ #include -#ifdef USE_LIBIDN -#include +#ifdef USE_LIBIDN2 +#include #endif #ifdef USE_WINDOWS_SSPI @@ -53,7 +53,7 @@ const char * curl_easy_strerror(CURLcode error) { #ifndef CURL_DISABLE_VERBOSE_STRINGS - switch (error) { + switch(error) { case CURLE_OK: return "No error"; @@ -79,8 +79,8 @@ curl_easy_strerror(CURLcode error) case CURLE_COULDNT_CONNECT: return "Couldn't connect to server"; - case CURLE_FTP_WEIRD_SERVER_REPLY: - return "FTP: weird server reply"; + case CURLE_WEIRD_SERVER_REPLY: + return "Weird server reply"; case CURLE_REMOTE_ACCESS_DENIED: return "Access denied to remote resource"; @@ -348,7 +348,7 @@ const char * curl_multi_strerror(CURLMcode error) { #ifndef CURL_DISABLE_VERBOSE_STRINGS - switch (error) { + switch(error) { case CURLM_CALL_MULTI_PERFORM: return "Please call curl_multi_perform() soon"; @@ -393,7 +393,7 @@ const char * curl_share_strerror(CURLSHcode error) { #ifndef CURL_DISABLE_VERBOSE_STRINGS - switch (error) { + switch(error) { case CURLSHE_OK: return "No error"; @@ -427,7 +427,7 @@ curl_share_strerror(CURLSHcode error) #ifdef USE_WINSOCK -/* This function handles most / all (?) Winsock errors cURL is able to produce. +/* This function handles most / all (?) Winsock errors curl is able to produce. */ static const char * get_winsock_error (int err, char *buf, size_t len) @@ -435,7 +435,7 @@ get_winsock_error (int err, char *buf, size_t len) const char *p; #ifndef CURL_DISABLE_VERBOSE_STRINGS - switch (err) { + switch(err) { case WSAEINTR: p = "Call interrupted"; break; @@ -609,7 +609,7 @@ get_winsock_error (int err, char *buf, size_t len) else p = "error"; #endif - strncpy (buf, p, len); + strncpy(buf, p, len); buf [len-1] = '\0'; return buf; } @@ -715,10 +715,12 @@ const char *Curl_strerror(struct connectdata *conn, int err) buf[max] = '\0'; /* make sure the string is zero terminated */ /* strip trailing '\r\n' or '\n'. */ - if((p = strrchr(buf, '\n')) != NULL && (p - buf) >= 2) - *p = '\0'; - if((p = strrchr(buf, '\r')) != NULL && (p - buf) >= 1) - *p = '\0'; + p = strrchr(buf, '\n'); + if(p && (p - buf) >= 2) + *p = '\0'; + p = strrchr(buf, '\r'); + if(p && (p - buf) >= 1) + *p = '\0'; if(old_errno != ERRNO) SET_ERRNO(old_errno); @@ -726,83 +728,6 @@ const char *Curl_strerror(struct connectdata *conn, int err) return buf; } -#ifdef USE_LIBIDN -/* - * Return error-string for libidn status as returned from idna_to_ascii_lz(). - */ -const char *Curl_idn_strerror (struct connectdata *conn, int err) -{ -#ifdef HAVE_IDNA_STRERROR - (void)conn; - return idna_strerror((Idna_rc) err); -#else - const char *str; - char *buf; - size_t max; - - DEBUGASSERT(conn); - - buf = conn->syserr_buf; - max = sizeof(conn->syserr_buf)-1; - *buf = '\0'; - -#ifndef CURL_DISABLE_VERBOSE_STRINGS - switch ((Idna_rc)err) { - case IDNA_SUCCESS: - str = "No error"; - break; - case IDNA_STRINGPREP_ERROR: - str = "Error in string preparation"; - break; - case IDNA_PUNYCODE_ERROR: - str = "Error in Punycode operation"; - break; - case IDNA_CONTAINS_NON_LDH: - str = "Illegal ASCII characters"; - break; - case IDNA_CONTAINS_MINUS: - str = "Contains minus"; - break; - case IDNA_INVALID_LENGTH: - str = "Invalid output length"; - break; - case IDNA_NO_ACE_PREFIX: - str = "No ACE prefix (\"xn--\")"; - break; - case IDNA_ROUNDTRIP_VERIFY_ERROR: - str = "Round trip verify error"; - break; - case IDNA_CONTAINS_ACE_PREFIX: - str = "Already have ACE prefix (\"xn--\")"; - break; - case IDNA_ICONV_ERROR: - str = "Locale conversion failed"; - break; - case IDNA_MALLOC_ERROR: - str = "Allocation failed"; - break; - case IDNA_DLOPEN_ERROR: - str = "dlopen() error"; - break; - default: - snprintf(buf, max, "error %d", err); - str = NULL; - break; - } -#else - if((Idna_rc)err == IDNA_SUCCESS) - str = "No error"; - else - str = "Error"; -#endif - if(str) - strncpy(buf, str, max); - buf[max] = '\0'; - return (buf); -#endif -} -#endif /* USE_LIBIDN */ - #ifdef USE_WINDOWS_SSPI const char *Curl_sspi_strerror (struct connectdata *conn, int err) { @@ -827,7 +752,7 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err) old_errno = ERRNO; - switch (err) { + switch(err) { case SEC_E_OK: txt = "No error"; break; @@ -1112,10 +1037,12 @@ const char *Curl_sspi_strerror (struct connectdata *conn, int err) if(msg_formatted) { msgbuf[sizeof(msgbuf)-1] = '\0'; /* strip trailing '\r\n' or '\n' */ - if((p = strrchr(msgbuf, '\n')) != NULL && (p - msgbuf) >= 2) - *p = '\0'; - if((p = strrchr(msgbuf, '\r')) != NULL && (p - msgbuf) >= 1) - *p = '\0'; + p = strrchr(msgbuf, '\n'); + if(p && (p - msgbuf) >= 2) + *p = '\0'; + p = strrchr(msgbuf, '\r'); + if(p && (p - msgbuf) >= 1) + *p = '\0'; msg = msgbuf; } if(msg) diff --git a/contrib/curl/lib/strerror.h b/contrib/curl/lib/strerror.h index ae8c96bd..627273eb 100644 --- a/contrib/curl/lib/strerror.h +++ b/contrib/curl/lib/strerror.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,7 +26,7 @@ const char *Curl_strerror (struct connectdata *conn, int err); -#ifdef USE_LIBIDN +#ifdef USE_LIBIDN2 const char *Curl_idn_strerror (struct connectdata *conn, int err); #endif diff --git a/contrib/curl/lib/strtoofft.c b/contrib/curl/lib/strtoofft.c index 6d5d2d5c..b854bf4d 100644 --- a/contrib/curl/lib/strtoofft.c +++ b/contrib/curl/lib/strtoofft.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -165,7 +165,7 @@ static int get_char(char c, int base) value = c - 'a' + 10; } #else - const char * cp; + const char *cp; int value; cp = memchr(valchars, c, 10 + 26 + 26); diff --git a/contrib/curl/lib/system_win32.c b/contrib/curl/lib/system_win32.c index 73d30b42..78737593 100644 --- a/contrib/curl/lib/system_win32.c +++ b/contrib/curl/lib/system_win32.c @@ -24,9 +24,6 @@ #if defined(WIN32) -#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \ - defined(USE_WINSOCK)) - #include #include "system_win32.h" @@ -34,6 +31,10 @@ #include "curl_memory.h" #include "memdebug.h" +#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \ + defined(USE_WINSOCK)) + + #if !defined(LOAD_WITH_ALTERED_SEARCH_PATH) #define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008 #endif @@ -56,6 +57,201 @@ typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD); # define LOADLIBARYEX "LoadLibraryExA" #endif +#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */ + +/* + * Curl_verify_windows_version() + * + * This is used to verify if we are running on a specific windows version. + * + * Parameters: + * + * majorVersion [in] - The major version number. + * minorVersion [in] - The minor version number. + * platform [in] - The optional platform identifer. + * condition [in] - The test condition used to specifier whether we are + * checking a version less then, equal to or greater than + * what is specified in the major and minor version + * numbers. + * + * Returns TRUE if matched; otherwise FALSE. + */ +bool Curl_verify_windows_version(const unsigned int majorVersion, + const unsigned int minorVersion, + const PlatformIdentifier platform, + const VersionCondition condition) +{ + bool matched = FALSE; + +#if defined(CURL_WINDOWS_APP) + /* We have no way to determine the Windows version from Windows apps, + so let's assume we're running on the target Windows version. */ + const WORD fullVersion = MAKEWORD(minorVersion, majorVersion); + const WORD targetVersion = (WORD)_WIN32_WINNT; + + switch(condition) { + case VERSION_LESS_THAN: + matched = targetVersion < fullVersion; + break; + + case VERSION_LESS_THAN_EQUAL: + matched = targetVersion <= fullVersion; + break; + + case VERSION_EQUAL: + matched = targetVersion == fullVersion; + break; + + case VERSION_GREATER_THAN_EQUAL: + matched = targetVersion >= fullVersion; + break; + + case VERSION_GREATER_THAN: + matched = targetVersion > fullVersion; + break; + } + + if(matched && (platform == PLATFORM_WINDOWS)) { + /* we're always running on PLATFORM_WINNT */ + matched = FALSE; + } +#elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ + (_WIN32_WINNT < _WIN32_WINNT_WIN2K) + OSVERSIONINFO osver; + + memset(&osver, 0, sizeof(osver)); + osver.dwOSVersionInfoSize = sizeof(osver); + + /* Find out Windows version */ + if(GetVersionEx(&osver)) { + /* Verify the Operating System version number */ + switch(condition) { + case VERSION_LESS_THAN: + if(osver.dwMajorVersion < majorVersion || + (osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion < minorVersion)) + matched = TRUE; + break; + + case VERSION_LESS_THAN_EQUAL: + if(osver.dwMajorVersion <= majorVersion && + osver.dwMinorVersion <= minorVersion) + matched = TRUE; + break; + + case VERSION_EQUAL: + if(osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion == minorVersion) + matched = TRUE; + break; + + case VERSION_GREATER_THAN_EQUAL: + if(osver.dwMajorVersion >= majorVersion && + osver.dwMinorVersion >= minorVersion) + matched = TRUE; + break; + + case VERSION_GREATER_THAN: + if(osver.dwMajorVersion > majorVersion || + (osver.dwMajorVersion == majorVersion && + osver.dwMinorVersion > minorVersion)) + matched = TRUE; + break; + } + + /* Verify the platform identifier (if necessary) */ + if(matched) { + switch(platform) { + case PLATFORM_WINDOWS: + if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS) + matched = FALSE; + break; + + case PLATFORM_WINNT: + if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT) + matched = FALSE; + + default: /* like platform == PLATFORM_DONT_CARE */ + break; + } + } + } +#else + ULONGLONG cm = 0; + OSVERSIONINFOEX osver; + BYTE majorCondition; + BYTE minorCondition; + BYTE spMajorCondition; + BYTE spMinorCondition; + + switch(condition) { + case VERSION_LESS_THAN: + majorCondition = VER_LESS; + minorCondition = VER_LESS; + spMajorCondition = VER_LESS_EQUAL; + spMinorCondition = VER_LESS_EQUAL; + break; + + case VERSION_LESS_THAN_EQUAL: + majorCondition = VER_LESS_EQUAL; + minorCondition = VER_LESS_EQUAL; + spMajorCondition = VER_LESS_EQUAL; + spMinorCondition = VER_LESS_EQUAL; + break; + + case VERSION_EQUAL: + majorCondition = VER_EQUAL; + minorCondition = VER_EQUAL; + spMajorCondition = VER_GREATER_EQUAL; + spMinorCondition = VER_GREATER_EQUAL; + break; + + case VERSION_GREATER_THAN_EQUAL: + majorCondition = VER_GREATER_EQUAL; + minorCondition = VER_GREATER_EQUAL; + spMajorCondition = VER_GREATER_EQUAL; + spMinorCondition = VER_GREATER_EQUAL; + break; + + case VERSION_GREATER_THAN: + majorCondition = VER_GREATER; + minorCondition = VER_GREATER; + spMajorCondition = VER_GREATER_EQUAL; + spMinorCondition = VER_GREATER_EQUAL; + break; + + default: + return FALSE; + } + + memset(&osver, 0, sizeof(osver)); + osver.dwOSVersionInfoSize = sizeof(osver); + osver.dwMajorVersion = majorVersion; + osver.dwMinorVersion = minorVersion; + if(platform == PLATFORM_WINDOWS) + osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS; + else if(platform == PLATFORM_WINNT) + osver.dwPlatformId = VER_PLATFORM_WIN32_NT; + + cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition); + cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition); + cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition); + if(platform != PLATFORM_DONT_CARE) + cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL); + + if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION | + VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), + cm)) + matched = TRUE; +#endif + + return matched; +} + +#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \ + defined(USE_WINSOCK)) + /* * Curl_load_library() * @@ -88,10 +284,12 @@ HMODULE Curl_load_library(LPCTSTR filename) there is. Note: Both back slashes and forward slashes have been supported since the earlier days of DOS at an API level although they are not supported by command prompt */ - if(_tcspbrk(filename, TEXT("\\/"))) + if(_tcspbrk(filename, TEXT("\\/"))) { + /** !checksrc! disable BANNEDFUNC 1 **/ hModule = pLoadLibraryEx ? pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) : LoadLibrary(filename); + } /* Detect if KB2533623 is installed, as LOAD_LIBARY_SEARCH_SYSTEM32 is only supported on Windows Vista, Windows Server 2008, Windows 7 and Windows Server 2008 R2 with this patch or natively on Windows 8 and above */ @@ -113,12 +311,13 @@ HMODULE Curl_load_library(LPCTSTR filename) _tcscpy(path + _tcslen(path), filename); /* Load the DLL from the Windows system directory */ + /** !checksrc! disable BANNEDFUNC 1 **/ hModule = pLoadLibraryEx ? pLoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) : LoadLibrary(path); - free(path); } + free(path); } } diff --git a/contrib/curl/lib/system_win32.h b/contrib/curl/lib/system_win32.h index dec18899..1e772856 100644 --- a/contrib/curl/lib/system_win32.h +++ b/contrib/curl/lib/system_win32.h @@ -26,6 +26,28 @@ #if defined(WIN32) +/* Version condition */ +typedef enum { + VERSION_LESS_THAN, + VERSION_LESS_THAN_EQUAL, + VERSION_EQUAL, + VERSION_GREATER_THAN_EQUAL, + VERSION_GREATER_THAN +} VersionCondition; + +/* Platform identifier */ +typedef enum { + PLATFORM_DONT_CARE, + PLATFORM_WINDOWS, + PLATFORM_WINNT +} PlatformIdentifier; + +/* This is used to verify if we are running on a specific windows version */ +bool Curl_verify_windows_version(const unsigned int majorVersion, + const unsigned int minorVersion, + const PlatformIdentifier platform, + const VersionCondition condition); + #if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \ defined(USE_WINSOCK)) diff --git a/contrib/curl/lib/telnet.c b/contrib/curl/lib/telnet.c index 870a1b82..162cab75 100644 --- a/contrib/curl/lib/telnet.c +++ b/contrib/curl/lib/telnet.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -58,8 +58,7 @@ #include "arpa_telnet.h" #include "select.h" -#include "strequal.h" -#include "rawstr.h" +#include "strcase.h" #include "warnless.h" /* The last 3 #include files should be in this order */ @@ -92,7 +91,7 @@ #ifdef USE_WINSOCK typedef FARPROC WSOCK2_FUNC; -static CURLcode check_wsock2 (struct SessionHandle *data); +static CURLcode check_wsock2(struct Curl_easy *data); #endif static @@ -101,7 +100,7 @@ CURLcode telrcv(struct connectdata *, ssize_t count); /* Number of bytes received */ #ifndef CURL_DISABLE_VERBOSE_STRINGS -static void printoption(struct SessionHandle *data, +static void printoption(struct Curl_easy *data, const char *direction, int cmd, int option); #endif @@ -111,7 +110,7 @@ static void send_negotiation(struct connectdata *, int cmd, int option); static void set_local_option(struct connectdata *, int cmd, int option); static void set_remote_option(struct connectdata *, int cmd, int option); -static void printsub(struct SessionHandle *data, +static void printsub(struct Curl_easy *data, int direction, unsigned char *pointer, size_t length); static void suboption(struct connectdata *); @@ -199,7 +198,7 @@ const struct Curl_handler Curl_handler_telnet = { #ifdef USE_WINSOCK static CURLcode -check_wsock2(struct SessionHandle *data) +check_wsock2(struct Curl_easy *data) { int err; WORD wVersionRequested; @@ -306,7 +305,7 @@ static void negotiate(struct connectdata *conn) } #ifndef CURL_DISABLE_VERBOSE_STRINGS -static void printoption(struct SessionHandle *data, +static void printoption(struct Curl_easy *data, const char *direction, int cmd, int option) { const char *fmt; @@ -347,7 +346,7 @@ static void send_negotiation(struct connectdata *conn, int cmd, int option) unsigned char buf[3]; ssize_t bytes_written; int err; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; buf[0] = CURL_IAC; buf[1] = (unsigned char)cmd; @@ -703,7 +702,7 @@ void rec_dont(struct connectdata *conn, int option) } -static void printsub(struct SessionHandle *data, +static void printsub(struct Curl_easy *data, int direction, /* '<' or '>' */ unsigned char *pointer, /* where suboption data is */ size_t length) /* length of suboption data */ @@ -822,7 +821,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) struct curl_slist *beg; char option_keyword[128] = ""; char option_arg[256] = ""; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct TELNET *tn = (struct TELNET *)conn->data->req.protop; CURLcode result = CURLE_OK; int binary_option; @@ -846,7 +845,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) option_keyword, option_arg) == 2) { /* Terminal type */ - if(Curl_raw_equal(option_keyword, "TTYPE")) { + if(strcasecompare(option_keyword, "TTYPE")) { strncpy(tn->subopt_ttype, option_arg, 31); tn->subopt_ttype[31] = 0; /* String termination */ tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES; @@ -854,7 +853,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) } /* Display variable */ - if(Curl_raw_equal(option_keyword, "XDISPLOC")) { + if(strcasecompare(option_keyword, "XDISPLOC")) { strncpy(tn->subopt_xdisploc, option_arg, 127); tn->subopt_xdisploc[127] = 0; /* String termination */ tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES; @@ -862,7 +861,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) } /* Environment variable */ - if(Curl_raw_equal(option_keyword, "NEW_ENV")) { + if(strcasecompare(option_keyword, "NEW_ENV")) { beg = curl_slist_append(tn->telnet_vars, option_arg); if(!beg) { result = CURLE_OUT_OF_MEMORY; @@ -874,7 +873,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) } /* Window Size */ - if(Curl_raw_equal(option_keyword, "WS")) { + if(strcasecompare(option_keyword, "WS")) { if(sscanf(option_arg, "%hu%*[xX]%hu", &tn->subopt_wsx, &tn->subopt_wsy) == 2) tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES; @@ -887,7 +886,7 @@ static CURLcode check_telnet_options(struct connectdata *conn) } /* To take care or not of the 8th bit in data exchange */ - if(Curl_raw_equal(option_keyword, "BINARY")) { + if(strcasecompare(option_keyword, "BINARY")) { binary_option=atoi(option_arg); if(binary_option!=1) { tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO; @@ -932,11 +931,11 @@ static void suboption(struct connectdata *conn) int err; char varname[128] = ""; char varval[128] = ""; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct TELNET *tn = (struct TELNET *)data->req.protop; printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2); - switch (CURL_SB_GET(tn)) { + switch(CURL_SB_GET(tn)) { case CURL_TELOPT_TTYPE: len = strlen(tn->subopt_ttype) + 4 + 2; snprintf((char *)temp, sizeof(temp), @@ -1005,12 +1004,12 @@ static void sendsuboption(struct connectdata *conn, int option) ssize_t bytes_written; int err; unsigned short x, y; - unsigned char*uc1, *uc2; + unsigned char *uc1, *uc2; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct TELNET *tn = (struct TELNET *)data->req.protop; - switch (option) { + switch(option) { case CURL_TELOPT_NAWS: /* We prepare data to be sent */ CURL_SB_CLEAR(tn); @@ -1021,8 +1020,8 @@ static void sendsuboption(struct connectdata *conn, int option) /* Window size must be sent according to the 'network order' */ x=htons(tn->subopt_wsx); y=htons(tn->subopt_wsy); - uc1 = (unsigned char*)&x; - uc2 = (unsigned char*)&y; + uc1 = (unsigned char *)&x; + uc2 = (unsigned char *)&y; CURL_SB_ACCUM(tn, uc1[0]); CURL_SB_ACCUM(tn, uc1[1]); CURL_SB_ACCUM(tn, uc2[0]); @@ -1065,7 +1064,7 @@ CURLcode telrcv(struct connectdata *conn, CURLcode result; int in = 0; int startwrite=-1; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct TELNET *tn = (struct TELNET *)data->req.protop; #define startskipping() \ @@ -1088,7 +1087,7 @@ CURLcode telrcv(struct connectdata *conn, while(count--) { c = inbuf[in]; - switch (tn->telrcv_state) { + switch(tn->telrcv_state) { case CURL_TS_CR: tn->telrcv_state = CURL_TS_DATA; if(c == '\0') { @@ -1112,7 +1111,7 @@ CURLcode telrcv(struct connectdata *conn, case CURL_TS_IAC: process_iac: DEBUGASSERT(startwrite < 0); - switch (c) { + switch(c) { case CURL_WILL: tn->telrcv_state = CURL_TS_WILL; break; @@ -1187,7 +1186,7 @@ CURLcode telrcv(struct connectdata *conn, * IAC SE was left off, or another option got inserted into the * suboption are all possibilities. If we assume that the IAC was * not doubled, and really the IAC SE was left off, we could get - * into an infinate loop here. So, instead, we terminate the + * into an infinite loop here. So, instead, we terminate the * suboption, and process the partial suboption if we can. */ CURL_SB_ACCUM(tn, CURL_IAC); @@ -1242,7 +1241,7 @@ static CURLcode send_telnet_data(struct connectdata *conn, struct pollfd pfd[1]; pfd[0].fd = conn->sock[FIRSTSOCKET]; pfd[0].events = POLLOUT; - switch (Curl_poll(pfd, 1, -1)) { + switch(Curl_poll(pfd, 1, -1)) { case -1: /* error, abort writing */ case 0: /* timeout (will never happen) */ result = CURLE_SEND_ERROR; @@ -1282,7 +1281,7 @@ static CURLcode telnet_done(struct connectdata *conn, static CURLcode telnet_do(struct connectdata *conn, bool *done) { CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; #ifdef USE_WINSOCK HMODULE wsock2; @@ -1327,7 +1326,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) #ifdef USE_WINSOCK /* ** This functionality only works with WinSock >= 2.0. So, - ** make sure have it. + ** make sure we have it. */ result = check_wsock2(data); if(result) @@ -1417,6 +1416,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) /* Keep on listening and act on events */ while(keepon) { + const DWORD buf_size = (DWORD)CURL_BUFSIZE(data->set.buffer_size); waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout); switch(waitret) { case WAIT_TIMEOUT: @@ -1452,7 +1452,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) if(!readfile_read) break; - if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), + if(!ReadFile(stdin_handle, buf, buf_size, &readfile_read, NULL)) { keepon = FALSE; result = CURLE_READ_ERROR; @@ -1471,7 +1471,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) case WAIT_OBJECT_0 + 1: { - if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), + if(!ReadFile(stdin_handle, buf, buf_size, &readfile_read, NULL)) { keepon = FALSE; result = CURLE_READ_ERROR; @@ -1490,7 +1490,8 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) events.lNetworkEvents = 0; if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) { - if((err = SOCKERRNO) != EINPROGRESS) { + err = SOCKERRNO; + if(err != EINPROGRESS) { infof(data, "WSAEnumNetworkEvents failed (%d)", err); keepon = FALSE; result = CURLE_READ_ERROR; @@ -1577,7 +1578,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) } while(keepon) { - switch (Curl_poll(pfd, poll_cnt, interval_ms)) { + switch(Curl_poll(pfd, poll_cnt, interval_ms)) { case -1: /* error, stop reading */ keepon = FALSE; continue; diff --git a/contrib/curl/lib/tftp.c b/contrib/curl/lib/tftp.c index 3c3eb5e1..f2f83477 100644 --- a/contrib/curl/lib/tftp.c +++ b/contrib/curl/lib/tftp.c @@ -55,9 +55,10 @@ #include "sockaddr.h" /* required for Curl_sockaddr_storage */ #include "multiif.h" #include "url.h" -#include "rawstr.h" +#include "strcase.h" #include "speedcheck.h" #include "select.h" +#include "escape.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -198,7 +199,7 @@ const struct Curl_handler Curl_handler_tftp = { static CURLcode tftp_set_timeouts(tftp_state_data_t *state) { time_t maxtime, timeout; - long timeout_ms; + time_t timeout_ms; bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE; time(&state->start_time); @@ -303,7 +304,7 @@ static unsigned short getrpacketblock(const tftp_packet_t *packet) static size_t Curl_strnlen(const char *string, size_t maxlen) { - const char *end = memchr (string, '\0', maxlen); + const char *end = memchr(string, '\0', maxlen); return end ? (size_t) (end - string) : maxlen; } @@ -333,7 +334,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state, const char *ptr, int len) { const char *tmp = ptr; - struct SessionHandle *data = state->conn->data; + struct Curl_easy *data = state->conn->data; /* if OACK doesn't contain blksize option, the default (512) must be used */ state->blksize = TFTP_BLKSIZE_DEFAULT; @@ -416,7 +417,7 @@ static CURLcode tftp_connect_for_tx(tftp_state_data_t *state, { CURLcode result; #ifndef CURL_DISABLE_VERBOSE_STRINGS - struct SessionHandle *data = state->conn->data; + struct Curl_easy *data = state->conn->data; infof(data, "%s\n", "Connected for transmit"); #endif @@ -432,7 +433,7 @@ static CURLcode tftp_connect_for_rx(tftp_state_data_t *state, { CURLcode result; #ifndef CURL_DISABLE_VERBOSE_STRINGS - struct SessionHandle *data = state->conn->data; + struct Curl_easy *data = state->conn->data; infof(data, "%s\n", "Connected for receive"); #endif @@ -450,7 +451,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) const char *mode = "octet"; char *filename; char buf[64]; - struct SessionHandle *data = state->conn->data; + struct Curl_easy *data = state->conn->data; CURLcode result = CURLE_OK; /* Set ascii mode if -B flag was used */ @@ -484,10 +485,10 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) /* As RFC3617 describes the separator slash is not actually part of the file name so we skip the always-present first letter of the path string. */ - filename = curl_easy_unescape(data, &state->conn->data->state.path[1], 0, - NULL); - if(!filename) - return CURLE_OUT_OF_MEMORY; + result = Curl_urldecode(data, &state->conn->data->state.path[1], 0, + &filename, NULL, FALSE); + if(result) + return result; snprintf((char *)state->spacket.data+2, state->blksize, @@ -581,7 +582,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) { ssize_t sbytes; int rblock; - struct SessionHandle *data = state->conn->data; + struct Curl_easy *data = state->conn->data; switch(event) { @@ -700,11 +701,12 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) **********************************************************/ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) { - struct SessionHandle *data = state->conn->data; + struct Curl_easy *data = state->conn->data; ssize_t sbytes; int rblock; CURLcode result = CURLE_OK; struct SingleRequest *k = &data->req; + int cb; /* Bytes currently read */ switch(event) { @@ -762,9 +764,20 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) return CURLE_OK; } - result = Curl_fillreadbuffer(state->conn, state->blksize, &state->sbytes); - if(result) - return result; + /* TFTP considers data block size < 512 bytes as an end of session. So + * in some cases we must wait for additional data to build full (512 bytes) + * data block. + * */ + state->sbytes = 0; + state->conn->data->req.upload_fromhere = (char *)state->spacket.data+4; + do { + result = Curl_fillreadbuffer(state->conn, state->blksize - state->sbytes, + &cb); + if(result) + return result; + state->sbytes += cb; + state->conn->data->req.upload_fromhere += cb; + } while(state->sbytes < state->blksize && cb != 0); sbytes = sendto(state->sockfd, (void *) state->spacket.data, 4 + state->sbytes, SEND_4TH_ARG, @@ -889,7 +902,7 @@ static CURLcode tftp_state_machine(tftp_state_data_t *state, tftp_event_t event) { CURLcode result = CURLE_OK; - struct SessionHandle *data = state->conn->data; + struct Curl_easy *data = state->conn->data; switch(state->state) { case TFTP_STATE_START: @@ -1081,7 +1094,7 @@ static CURLcode tftp_receive_packet(struct connectdata *conn) struct Curl_sockaddr_storage fromaddr; curl_socklen_t fromlen; CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; struct SingleRequest *k = &data->req; @@ -1200,7 +1213,7 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) int rc; tftp_event_t event; CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc; long timeout_ms = tftp_state_timeout(conn, &event); @@ -1221,7 +1234,7 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) } else { /* no timeouts to handle, check our socket */ - rc = Curl_socket_ready(state->sockfd, CURL_SOCKET_BAD, 0); + rc = SOCKET_READABLE(state->sockfd, 0); if(rc == -1) { /* bail out */ @@ -1342,8 +1355,8 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done) static CURLcode tftp_setup_connection(struct connectdata * conn) { - struct SessionHandle *data = conn->data; - char * type; + struct Curl_easy *data = conn->data; + char *type; char command; conn->socktype = SOCK_DGRAM; /* UDP datagram based */ @@ -1359,7 +1372,7 @@ static CURLcode tftp_setup_connection(struct connectdata * conn) *type = 0; /* it was in the middle of the hostname */ command = Curl_raw_toupper(type[6]); - switch (command) { + switch(command) { case 'A': /* ASCII mode */ case 'N': /* NETASCII mode */ data->set.prefer_ascii = TRUE; diff --git a/contrib/curl/lib/timeval.c b/contrib/curl/lib/timeval.c index 629f1c8f..f3b207a3 100644 --- a/contrib/curl/lib/timeval.c +++ b/contrib/curl/lib/timeval.c @@ -116,7 +116,7 @@ struct timeval curlx_tvnow(void) * Returns: the time difference in number of milliseconds. For large diffs it * returns 0x7fffffff on 32bit time_t systems. */ -long curlx_tvdiff(struct timeval newer, struct timeval older) +time_t curlx_tvdiff(struct timeval newer, struct timeval older) { #if SIZEOF_TIME_T < 8 /* for 32bit time_t systems, add a precaution to avoid overflow for really @@ -126,7 +126,7 @@ long curlx_tvdiff(struct timeval newer, struct timeval older) return 0x7fffffff; #endif return (newer.tv_sec-older.tv_sec)*1000+ - (long)(newer.tv_usec-older.tv_usec)/1000; + (time_t)(newer.tv_usec-older.tv_usec)/1000; } /* @@ -144,7 +144,7 @@ double curlx_tvdiff_secs(struct timeval newer, struct timeval older) } /* return the number of seconds in the given input timeval struct */ -long Curl_tvlong(struct timeval t1) +time_t Curl_tvlong(struct timeval t1) { return t1.tv_sec; } diff --git a/contrib/curl/lib/timeval.h b/contrib/curl/lib/timeval.h index 50c31a25..09f8b3a2 100644 --- a/contrib/curl/lib/timeval.h +++ b/contrib/curl/lib/timeval.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2007, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -37,7 +37,7 @@ struct timeval curlx_tvnow(void); * * Returns: the time difference in number of milliseconds. */ -long curlx_tvdiff(struct timeval t1, struct timeval t2); +time_t curlx_tvdiff(struct timeval t1, struct timeval t2); /* * Same as curlx_tvdiff but with full usec resolution. @@ -46,7 +46,7 @@ long curlx_tvdiff(struct timeval t1, struct timeval t2); */ double curlx_tvdiff_secs(struct timeval t1, struct timeval t2); -long Curl_tvlong(struct timeval t1); +time_t Curl_tvlong(struct timeval t1); /* These two defines below exist to provide the older API for library internals only. */ diff --git a/contrib/curl/lib/transfer.c b/contrib/curl/lib/transfer.c index 4a12ee9a..a577bf72 100644 --- a/contrib/curl/lib/transfer.c +++ b/contrib/curl/lib/transfer.c @@ -21,10 +21,7 @@ ***************************************************************************/ #include "curl_setup.h" - #include "strtoofft.h" -#include "strequal.h" -#include "rawstr.h" #ifdef HAVE_NETINET_IN_H #include @@ -75,6 +72,7 @@ #include "multiif.h" #include "connect.h" #include "non-ascii.h" +#include "http2.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -87,7 +85,7 @@ */ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; size_t buffersize = (size_t)bytes; int nread; #ifdef CURL_DOES_CONVERSIONS @@ -242,7 +240,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) */ CURLcode Curl_readrewind(struct connectdata *conn) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; conn->bits.rewindaftersend = FALSE; /* we rewind now */ @@ -352,7 +350,7 @@ static void read_rewind(struct connectdata *conn, * Check to see if CURLOPT_TIMECONDITION was met by comparing the time of the * remote document with the time provided by CURLOPT_TIMEVAL */ -bool Curl_meets_timecondition(struct SessionHandle *data, time_t timeofdoc) +bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc) { if((timeofdoc == 0) || (data->set.timevalue == 0)) return TRUE; @@ -384,11 +382,15 @@ bool Curl_meets_timecondition(struct SessionHandle *data, time_t timeofdoc) * Go ahead and do a read if we have a readable socket or if * the stream was rewound (in which case we have data in a * buffer) + * + * return '*comeback' TRUE if we didn't properly drain the socket so this + * function should get called again without select() or similar in between! */ -static CURLcode readwrite_data(struct SessionHandle *data, +static CURLcode readwrite_data(struct Curl_easy *data, struct connectdata *conn, struct SingleRequest *k, - int *didwhat, bool *done) + int *didwhat, bool *done, + bool *comeback) { CURLcode result = CURLE_OK; ssize_t nread; /* number of bytes read */ @@ -398,6 +400,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, int maxloops = 100; *done = FALSE; + *comeback = FALSE; /* This is where we loop until we have read everything there is to read or we get a CURLE_AGAIN */ @@ -529,6 +532,13 @@ static CURLcode readwrite_data(struct SessionHandle *data, is non-headers. */ if(k->str && !k->header && (nread > 0 || is_empty_data)) { + if(data->set.opt_no_body) { + /* data arrives although we want none, bail out */ + streamclose(conn, "ignoring body"); + *done = TRUE; + return CURLE_WEIRD_SERVER_REPLY; + } + #ifndef CURL_DISABLE_HTTP if(0 == k->bodywrites && !is_empty_data) { /* These checks are only made the first time we are about to @@ -731,8 +741,8 @@ static CURLcode readwrite_data(struct SessionHandle *data, Make sure that ALL_CONTENT_ENCODINGS contains all the encodings handled here. */ #ifdef HAVE_LIBZ - switch (conn->data->set.http_ce_skip ? - IDENTITY : k->auto_decoding) { + switch(conn->data->set.http_ce_skip ? + IDENTITY : k->auto_decoding) { case IDENTITY: #endif /* This is the default when the server sends no @@ -765,9 +775,9 @@ static CURLcode readwrite_data(struct SessionHandle *data, break; default: - failf (data, "Unrecognized content encoding type. " - "libcurl understands `identity', `deflate' and `gzip' " - "content encodings."); + failf(data, "Unrecognized content encoding type. " + "libcurl understands `identity', `deflate' and `gzip' " + "content encodings."); result = CURLE_BAD_CONTENT_ENCODING; break; } @@ -804,6 +814,12 @@ static CURLcode readwrite_data(struct SessionHandle *data, } while(data_pending(conn) && maxloops--); + if(maxloops <= 0) { + /* we mark it as read-again-please */ + conn->cselect_bits = CURL_CSELECT_IN; + *comeback = TRUE; + } + if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) && conn->bits.close) { /* When we've read the entire thing and the close bit is set, the server @@ -821,6 +837,8 @@ static CURLcode done_sending(struct connectdata *conn, { k->keepon &= ~KEEP_SEND; /* we're done writing */ + Curl_http2_done_sending(conn); + if(conn->bits.rewindaftersend) { CURLcode result = Curl_readrewind(conn); if(result) @@ -833,7 +851,7 @@ static CURLcode done_sending(struct connectdata *conn, /* * Send data to upload to the server, when the socket is writable. */ -static CURLcode readwrite_upload(struct SessionHandle *data, +static CURLcode readwrite_upload(struct Curl_easy *data, struct connectdata *conn, struct SingleRequest *k, int *didwhat) @@ -1029,10 +1047,14 @@ static CURLcode readwrite_upload(struct SessionHandle *data, /* * Curl_readwrite() is the low-level function to be called when data is to * be read and written to/from the connection. + * + * return '*comeback' TRUE if we didn't properly drain the socket so this + * function should get called again without select() or similar in between! */ CURLcode Curl_readwrite(struct connectdata *conn, - struct SessionHandle *data, - bool *done) + struct Curl_easy *data, + bool *done, + bool *comeback) { struct SingleRequest *k = &data->req; CURLcode result; @@ -1064,7 +1086,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, if(!select_res) /* Call for select()/poll() only, if read/write/error status is not known. */ - select_res = Curl_socket_ready(fd_read, fd_write, 0); + select_res = Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, 0); if(select_res == CURL_CSELECT_ERR) { failf(data, "select/poll returned error"); @@ -1077,7 +1099,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, if((k->keepon & KEEP_RECV) && ((select_res & CURL_CSELECT_IN) || conn->bits.stream_was_rewound)) { - result = readwrite_data(data, conn, k, &didwhat, done); + result = readwrite_data(data, conn, k, &didwhat, done, comeback); if(result || *done) return result; } @@ -1115,7 +1137,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, */ - long ms = Curl_tvdiff(k->now, k->start100); + time_t ms = Curl_tvdiff(k->now, k->start100); if(ms >= data->set.expect_100_timeout) { /* we've waited long enough, continue anyway */ k->exp100 = EXP100_SEND_DATA; @@ -1208,7 +1230,7 @@ int Curl_single_getsock(const struct connectdata *conn, of sockets */ int numsocks) { - const struct SessionHandle *data = conn->data; + const struct Curl_easy *data = conn->data; int bitmap = GETSOCK_BLANK; unsigned sockindex = 0; @@ -1249,63 +1271,9 @@ int Curl_single_getsock(const struct connectdata *conn, return bitmap; } -/* - * Determine optimum sleep time based on configured rate, current rate, - * and packet size. - * Returns value in milliseconds. - * - * The basic idea is to adjust the desired rate up/down in this method - * based on whether we are running too slow or too fast. Then, calculate - * how many milliseconds to wait for the next packet to achieve this new - * rate. - */ -long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, - int pkt_size) -{ - curl_off_t min_sleep = 0; - curl_off_t rv = 0; - - if(rate_bps == 0) - return 0; - - /* If running faster than about .1% of the desired speed, slow - * us down a bit. Use shift instead of division as the 0.1% - * cutoff is arbitrary anyway. - */ - if(cur_rate_bps > (rate_bps + (rate_bps >> 10))) { - /* running too fast, decrease target rate by 1/64th of rate */ - rate_bps -= rate_bps >> 6; - min_sleep = 1; - } - else if(cur_rate_bps < (rate_bps - (rate_bps >> 10))) { - /* running too slow, increase target rate by 1/64th of rate */ - rate_bps += rate_bps >> 6; - } - - /* Determine number of milliseconds to wait until we do - * the next packet at the adjusted rate. We should wait - * longer when using larger packets, for instance. - */ - rv = ((curl_off_t)(pkt_size * 1000) / rate_bps); - - /* Catch rounding errors and always slow down at least 1ms if - * we are running too fast. - */ - if(rv < min_sleep) - rv = min_sleep; - - /* Bound value to fit in 'long' on 32-bit platform. That's - * plenty long enough anyway! - */ - if(rv > 0x7fffffff) - rv = 0x7fffffff; - - return (long)rv; -} - /* Curl_init_CONNECT() gets called each time the handle switches to CONNECT which means this gets called once for each subsequent redirect etc */ -void Curl_init_CONNECT(struct SessionHandle *data) +void Curl_init_CONNECT(struct Curl_easy *data) { data->state.fread_func = data->set.fread_func_set; data->state.in = data->set.in_set; @@ -1316,7 +1284,7 @@ void Curl_init_CONNECT(struct SessionHandle *data) * once for one transfer no matter if it has redirects or do multi-pass * authentication etc. */ -CURLcode Curl_pretransfer(struct SessionHandle *data) +CURLcode Curl_pretransfer(struct Curl_easy *data) { CURLcode result; if(!data->change.url) { @@ -1328,7 +1296,7 @@ CURLcode Curl_pretransfer(struct SessionHandle *data) /* Init the SSL session ID cache here. We do it here since we want to do it after the *_setopt() calls (that could specify the size of the cache) but before any transfer takes place. */ - result = Curl_ssl_initsessions(data, data->set.ssl.max_ssl_sessions); + result = Curl_ssl_initsessions(data, data->set.general_ssl.max_ssl_sessions); if(result) return result; @@ -1403,7 +1371,7 @@ CURLcode Curl_pretransfer(struct SessionHandle *data) /* * Curl_posttransfer() is called immediately after a transfer ends */ -CURLcode Curl_posttransfer(struct SessionHandle *data) +CURLcode Curl_posttransfer(struct Curl_easy *data) { #if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL) /* restore the signal handler for SIGPIPE before we get back */ @@ -1660,7 +1628,7 @@ static char *concat_url(const char *base, const char *relurl) * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string * as given by the remote server and set up the new URL to request. */ -CURLcode Curl_follow(struct SessionHandle *data, +CURLcode Curl_follow(struct Curl_easy *data, char *newurl, /* this 'newurl' is the Location: string, and it must be malloc()ed before passed here */ @@ -1864,7 +1832,7 @@ CURLcode Curl_follow(struct SessionHandle *data, CURLcode Curl_retry_request(struct connectdata *conn, char **url) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; *url = NULL; @@ -1876,10 +1844,14 @@ CURLcode Curl_retry_request(struct connectdata *conn, if((data->req.bytecount + data->req.headerbytecount == 0) && conn->bits.reuse && - !data->set.opt_no_body && + (!data->set.opt_no_body + || (conn->handler->protocol & PROTO_FAMILY_HTTP)) && (data->set.rtspreq != RTSPREQ_RECEIVE)) { - /* We got no data, we attempted to re-use a connection and yet we want a - "body". This might happen if the connection was left alive when we were + /* We got no data, we attempted to re-use a connection. For HTTP this + can be a retry so we try again regardless if we expected a body. + For other protocols we only try again only if we expected a body. + + This might happen if the connection was left alive when we were done using it before, but that was closed when we wanted to read from it again. Bad luck. Retry the same request on a fresh connect! */ infof(conn->data, "Connection died, retrying a fresh connect\n"); @@ -1920,7 +1892,7 @@ Curl_setup_transfer( curl_off_t *writecountp /* return number of bytes written or NULL */ ) { - struct SessionHandle *data; + struct Curl_easy *data; struct SingleRequest *k; DEBUGASSERT(conn != NULL); diff --git a/contrib/curl/lib/transfer.h b/contrib/curl/lib/transfer.h index 802344f2..51896726 100644 --- a/contrib/curl/lib/transfer.h +++ b/contrib/curl/lib/transfer.h @@ -22,11 +22,11 @@ * ***************************************************************************/ -void Curl_init_CONNECT(struct SessionHandle *data); +void Curl_init_CONNECT(struct Curl_easy *data); -CURLcode Curl_pretransfer(struct SessionHandle *data); +CURLcode Curl_pretransfer(struct Curl_easy *data); CURLcode Curl_second_connect(struct connectdata *conn); -CURLcode Curl_posttransfer(struct SessionHandle *data); +CURLcode Curl_posttransfer(struct Curl_easy *data); typedef enum { FOLLOW_NONE, /* not used within the function, just a placeholder to @@ -38,19 +38,18 @@ typedef enum { FOLLOW_LAST /* never used */ } followtype; -CURLcode Curl_follow(struct SessionHandle *data, char *newurl, +CURLcode Curl_follow(struct Curl_easy *data, char *newurl, followtype type); - - CURLcode Curl_readwrite(struct connectdata *conn, - struct SessionHandle *data, bool *done); + struct Curl_easy *data, bool *done, + bool *comeback); int Curl_single_getsock(const struct connectdata *conn, curl_socket_t *socks, int numsocks); CURLcode Curl_readrewind(struct connectdata *conn); CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp); CURLcode Curl_retry_request(struct connectdata *conn, char **url); -bool Curl_meets_timecondition(struct SessionHandle *data, time_t timeofdoc); +bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc); /* This sets up a forthcoming transfer */ void @@ -65,8 +64,5 @@ Curl_setup_transfer (struct connectdata *data, curl_off_t *writecountp /* return number of bytes written */ ); -long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, - int pkt_size); - #endif /* HEADER_CURL_TRANSFER_H */ diff --git a/contrib/curl/lib/url.c b/contrib/curl/lib/url.c index 2a302665..38b9552f 100644 --- a/contrib/curl/lib/url.c +++ b/contrib/curl/lib/url.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -59,24 +59,13 @@ #include #endif -#ifdef USE_LIBIDN -#include -#include -#include -#ifdef HAVE_IDN_FREE_H -#include -#else -/* prototype from idn-free.h, not provided by libidn 0.4.5's make install! */ -void idn_free (void *ptr); -#endif -#ifndef HAVE_IDN_FREE -/* if idn_free() was not found in this version of libidn use free() instead */ -#define idn_free(x) (free)(x) -#endif +#ifdef USE_LIBIDN2 +#include + #elif defined(USE_WIN32_IDN) /* prototype for curl_win32_idn_to_ascii() */ bool curl_win32_idn_to_ascii(const char *in, char **out); -#endif /* USE_LIBIDN */ +#endif /* USE_LIBIDN2 */ #include "urldata.h" #include "netrc.h" @@ -88,7 +77,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "sendf.h" #include "progress.h" #include "cookie.h" -#include "strequal.h" +#include "strcase.h" #include "strerror.h" #include "escape.h" #include "strtok.h" @@ -100,10 +89,10 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); #include "multiif.h" #include "easyif.h" #include "speedcheck.h" -#include "rawstr.h" #include "warnless.h" #include "non-ascii.h" #include "inet_pton.h" +#include "getinfo.h" /* And now for the protocols */ #include "ftp.h" @@ -137,12 +126,12 @@ bool curl_win32_idn_to_ascii(const char *in, char **out); /* Local static prototypes */ static struct connectdata * -find_oldest_idle_connection_in_bundle(struct SessionHandle *data, +find_oldest_idle_connection_in_bundle(struct Curl_easy *data, struct connectbundle *bundle); static void conn_free(struct connectdata *conn); static void free_fixed_hostname(struct hostname *host); static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke); -static CURLcode parse_url_login(struct SessionHandle *data, +static CURLcode parse_url_login(struct Curl_easy *data, struct connectdata *conn, char **userptr, char **passwdptr, char **optionsptr); @@ -277,7 +266,7 @@ static const struct Curl_handler Curl_handler_dummy = { PROTOPT_NONE /* flags */ }; -void Curl_freeset(struct SessionHandle *data) +void Curl_freeset(struct Curl_easy *data) { /* Free all dynamic strings stored in the data->set substructure. */ enum dupstring i; @@ -355,7 +344,7 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp) return result; } -CURLcode Curl_dupset(struct SessionHandle *dst, struct SessionHandle *src) +CURLcode Curl_dupset(struct Curl_easy *dst, struct Curl_easy *src) { CURLcode result = CURLE_OK; enum dupstring i; @@ -398,14 +387,14 @@ CURLcode Curl_dupset(struct SessionHandle *dst, struct SessionHandle *src) * when curl_easy_perform() is invoked. */ -CURLcode Curl_close(struct SessionHandle *data) +CURLcode Curl_close(struct Curl_easy *data) { struct Curl_multi *m; if(!data) return CURLE_OK; - Curl_expire(data, 0); /* shut off timers */ + Curl_expire_clear(data); /* shut off timers */ m = data->multi; @@ -463,6 +452,7 @@ CURLcode Curl_close(struct SessionHandle *data) } data->change.url = NULL; + Curl_safefree(data->state.buffer); Curl_safefree(data->state.headerbuff); Curl_flush_cookies(data, 1); @@ -475,6 +465,7 @@ CURLcode Curl_close(struct SessionHandle *data) /* this destroys the channel and we cannot use it anymore after this */ Curl_resolver_cleanup(data->state.resolver); + Curl_http2_cleanup_dependencies(data); Curl_convert_close(data); /* No longer a dirty share, if it exists */ @@ -496,8 +487,8 @@ CURLcode Curl_close(struct SessionHandle *data) } /* - * Initialize the UserDefined fields within a SessionHandle. - * This may be safely called on a new or existing SessionHandle. + * Initialize the UserDefined fields within a Curl_easy. + * This may be safely called on a new or existing Curl_easy. */ CURLcode Curl_init_userdefined(struct UserDefined *set) { @@ -537,9 +528,9 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ /* Set the default size of the SSL session ID cache */ - set->ssl.max_ssl_sessions = 5; + set->general_ssl.max_ssl_sessions = 5; - set->proxyport = CURL_DEFAULT_PROXY_PORT; /* from url.h */ + set->proxyport = 0; set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */ set->httpauth = CURLAUTH_BASIC; /* defaults to basic */ set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */ @@ -551,14 +542,16 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) * libcurl 7.10 introduced SSL verification *by default*! This needs to be * switched off unless wanted. */ - set->ssl.verifypeer = TRUE; - set->ssl.verifyhost = TRUE; + set->ssl.primary.verifypeer = TRUE; + set->ssl.primary.verifyhost = TRUE; #ifdef USE_TLS_SRP set->ssl.authtype = CURL_TLSAUTH_NONE; #endif set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth type */ - set->ssl.sessionid = TRUE; /* session ID caching enabled by default */ + set->general_ssl.sessionid = TRUE; /* session ID caching enabled by + default */ + set->proxy_ssl = set->ssl; set->new_file_perms = 0644; /* Default permissions */ set->new_directory_perms = 0755; /* Default permissions */ @@ -581,12 +574,20 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) /* This is our preferred CA cert bundle/path since install time */ #if defined(CURL_CA_BUNDLE) - result = setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE); + result = setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE); + if(result) + return result; + + result = setstropt(&set->str[STRING_SSL_CAFILE_PROXY], CURL_CA_BUNDLE); if(result) return result; #endif #if defined(CURL_CA_PATH) - result = setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH); + result = setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH); + if(result) + return result; + + result = setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH); if(result) return result; #endif @@ -602,6 +603,7 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) set->tcp_keepintvl = 60; set->tcp_keepidle = 60; set->tcp_fastopen = FALSE; + set->tcp_nodelay = TRUE; set->ssl_enable_npn = TRUE; set->ssl_enable_alpn = TRUE; @@ -621,16 +623,16 @@ CURLcode Curl_init_userdefined(struct UserDefined *set) * @return CURLcode */ -CURLcode Curl_open(struct SessionHandle **curl) +CURLcode Curl_open(struct Curl_easy **curl) { CURLcode result; - struct SessionHandle *data; + struct Curl_easy *data; /* Very simple start-up: alloc the struct, init it with zeroes and return */ - data = calloc(1, sizeof(struct SessionHandle)); + data = calloc(1, sizeof(struct Curl_easy)); if(!data) { /* this is a very serious error */ - DEBUGF(fprintf(stderr, "Error: calloc of SessionHandle failed\n")); + DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n")); return CURLE_OUT_OF_MEMORY; } @@ -645,6 +647,12 @@ CURLcode Curl_open(struct SessionHandle **curl) /* We do some initial setup here, all those fields that can't be just 0 */ + data->state.buffer = malloc(BUFSIZE + 1); + if(!data->state.buffer) { + DEBUGF(fprintf(stderr, "Error: malloc of buffer failed\n")); + result = CURLE_OUT_OF_MEMORY; + } + data->state.headerbuff = malloc(HEADERSIZE); if(!data->state.headerbuff) { DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n")); @@ -657,6 +665,8 @@ CURLcode Curl_open(struct SessionHandle **curl) Curl_convert_init(data); + Curl_initinfo(data); + /* most recent connection is not yet defined */ data->state.lastconnect = NULL; @@ -673,6 +683,7 @@ CURLcode Curl_open(struct SessionHandle **curl) if(result) { Curl_resolver_cleanup(data->state.resolver); + free(data->state.buffer); free(data->state.headerbuff); Curl_freeset(data); free(data); @@ -684,7 +695,7 @@ CURLcode Curl_open(struct SessionHandle **curl) return result; } -CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, +CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, va_list param) { char *argptr; @@ -705,7 +716,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_SSL_CIPHER_LIST: /* set a list of cipher we want to use in the SSL connection */ - result = setstropt(&data->set.str[STRING_SSL_CIPHER_LIST], + result = setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_SSL_CIPHER_LIST: + /* set a list of cipher we want to use in the SSL connection for proxy */ + result = setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY], va_arg(param, char *)); break; @@ -781,6 +797,10 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ data->set.http_fail_on_error = (0 != va_arg(param, long)) ? TRUE : FALSE; break; + case CURLOPT_KEEP_SENDING_ON_ERROR: + data->set.http_keep_sending_on_error = (0 != va_arg(param, long)) ? + TRUE : FALSE; + break; case CURLOPT_UPLOAD: case CURLOPT_PUT: /* @@ -907,7 +927,18 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * implementations are lame. */ #ifdef USE_SSL - data->set.ssl.version = va_arg(param, long); + data->set.ssl.primary.version = va_arg(param, long); +#else + result = CURLE_UNKNOWN_OPTION; +#endif + break; + case CURLOPT_PROXY_SSLVERSION: + /* + * Set explicit SSL version to try to connect with for proxy, as some SSL + * implementations are lame. + */ +#ifdef USE_SSL + data->set.proxy_ssl.primary.version = va_arg(param, long); #else result = CURLE_UNKNOWN_OPTION; #endif @@ -1014,7 +1045,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, (data->set.postfieldsize > (curl_off_t)((size_t)-1)))) result = CURLE_OUT_OF_MEMORY; else { - char * p; + char *p; (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL); @@ -1225,23 +1256,23 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, if(argptr == NULL) break; - if(Curl_raw_equal(argptr, "ALL")) { + if(strcasecompare(argptr, "ALL")) { /* clear all cookies */ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_clearall(data->cookies); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } - else if(Curl_raw_equal(argptr, "SESS")) { + else if(strcasecompare(argptr, "SESS")) { /* clear session cookies */ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_clearsess(data->cookies); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } - else if(Curl_raw_equal(argptr, "FLUSH")) { + else if(strcasecompare(argptr, "FLUSH")) { /* flush cookies to file, takes care of the locking */ Curl_flush_cookies(data, 0); } - else if(Curl_raw_equal(argptr, "RELOAD")) { + else if(strcasecompare(argptr, "RELOAD")) { /* reload cookies from file */ Curl_cookie_loadfiles(data); break; @@ -1441,18 +1472,30 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, case CURLOPT_PROXY: /* - * Set proxy server:port to use as HTTP proxy. + * Set proxy server:port to use as proxy. * - * If the proxy is set to "" we explicitly say that we don't want to use a - * proxy (even though there might be environment variables saying so). + * If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL) + * we explicitly say that we don't want to use a proxy + * (even though there might be environment variables saying so). * * Setting it to NULL, means no proxy but allows the environment variables - * to decide for us. + * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL). */ result = setstropt(&data->set.str[STRING_PROXY], va_arg(param, char *)); break; + case CURLOPT_PRE_PROXY: + /* + * Set proxy server:port to use as SOCKS proxy. + * + * If the proxy is set to "" or NULL we explicitly say that we don't want + * to use the socks proxy. + */ + result = setstropt(&data->set.str[STRING_PRE_PROXY], + va_arg(param, char *)); + break; + case CURLOPT_PROXYTYPE: /* * Set proxy type. HTTP/HTTP_1_0/SOCKS4/SOCKS4a/SOCKS5/SOCKS5_HOSTNAME @@ -1464,7 +1507,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * set transfer mode (;type=) when doing FTP via an HTTP proxy */ - switch (va_arg(param, long)) { + switch(va_arg(param, long)) { case 0: data->set.proxy_transfer_mode = FALSE; break; @@ -1917,35 +1960,70 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * String that holds file name of the SSL certificate to use */ - result = setstropt(&data->set.str[STRING_CERT], + result = setstropt(&data->set.str[STRING_CERT_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_SSLCERT: + /* + * String that holds file name of the SSL certificate to use for proxy + */ + result = setstropt(&data->set.str[STRING_CERT_PROXY], va_arg(param, char *)); break; case CURLOPT_SSLCERTTYPE: /* * String that holds file type of the SSL certificate to use */ - result = setstropt(&data->set.str[STRING_CERT_TYPE], + result = setstropt(&data->set.str[STRING_CERT_TYPE_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_SSLCERTTYPE: + /* + * String that holds file type of the SSL certificate to use for proxy + */ + result = setstropt(&data->set.str[STRING_CERT_TYPE_PROXY], va_arg(param, char *)); break; case CURLOPT_SSLKEY: /* * String that holds file name of the SSL key to use */ - result = setstropt(&data->set.str[STRING_KEY], + result = setstropt(&data->set.str[STRING_KEY_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_SSLKEY: + /* + * String that holds file name of the SSL key to use for proxy + */ + result = setstropt(&data->set.str[STRING_KEY_PROXY], va_arg(param, char *)); break; case CURLOPT_SSLKEYTYPE: /* * String that holds file type of the SSL key to use */ - result = setstropt(&data->set.str[STRING_KEY_TYPE], + result = setstropt(&data->set.str[STRING_KEY_TYPE_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_SSLKEYTYPE: + /* + * String that holds file type of the SSL key to use for proxy + */ + result = setstropt(&data->set.str[STRING_KEY_TYPE_PROXY], va_arg(param, char *)); break; case CURLOPT_KEYPASSWD: /* * String that holds the SSL or SSH private key password. */ - result = setstropt(&data->set.str[STRING_KEY_PASSWD], + result = setstropt(&data->set.str[STRING_KEY_PASSWD_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_KEYPASSWD: + /* + * String that holds the SSL private key password for proxy. + */ + result = setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY], va_arg(param, char *)); break; case CURLOPT_SSLENGINE: @@ -2008,7 +2086,15 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Enable peer SSL verifying. */ - data->set.ssl.verifypeer = (0 != va_arg(param, long)) ? TRUE : FALSE; + data->set.ssl.primary.verifypeer = (0 != va_arg(param, long)) ? + TRUE : FALSE; + break; + case CURLOPT_PROXY_SSL_VERIFYPEER: + /* + * Enable peer SSL verifying for proxy. + */ + data->set.proxy_ssl.primary.verifypeer = + (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_SSL_VERIFYHOST: /* @@ -2026,7 +2112,25 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, return CURLE_BAD_FUNCTION_ARGUMENT; } - data->set.ssl.verifyhost = (0 != arg) ? TRUE : FALSE; + data->set.ssl.primary.verifyhost = (0 != arg) ? TRUE : FALSE; + break; + case CURLOPT_PROXY_SSL_VERIFYHOST: + /* + * Enable verification of the host name in the peer certificate for proxy + */ + arg = va_arg(param, long); + + /* Obviously people are not reading documentation and too many thought + this argument took a boolean when it wasn't and misused it. We thus ban + 1 as a sensible input and we warn about its use. Then we only have the + 2 action internally stored as TRUE. */ + + if(1 == arg) { + failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + + data->set.proxy_ssl.primary.verifyhost = (0 != arg)?TRUE:FALSE; break; case CURLOPT_SSL_VERIFYSTATUS: /* @@ -2037,7 +2141,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; } - data->set.ssl.verifystatus = (0 != va_arg(param, long)) ? TRUE : FALSE; + data->set.ssl.primary.verifystatus = (0 != va_arg(param, long)) ? + TRUE : FALSE; break; case CURLOPT_SSL_CTX_FUNCTION: #ifdef have_curlssl_ssl_ctx @@ -2083,7 +2188,19 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Set pinned public key for SSL connection. * Specify file name of the public key in DER format. */ - result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY], + result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG], + va_arg(param, char *)); +#else + result = CURLE_NOT_BUILT_IN; +#endif + break; + case CURLOPT_PROXY_PINNEDPUBLICKEY: +#ifdef have_curlssl_pinnedpubkey /* only by supported backends */ + /* + * Set pinned public key for SSL connection. + * Specify file name of the public key in DER format. + */ + result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY], va_arg(param, char *)); #else result = CURLE_NOT_BUILT_IN; @@ -2093,7 +2210,15 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Set CA info for SSL connection. Specify file name of the CA certificate */ - result = setstropt(&data->set.str[STRING_SSL_CAFILE], + result = setstropt(&data->set.str[STRING_SSL_CAFILE_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_CAINFO: + /* + * Set CA info SSL connection for proxy. Specify file name of the + * CA certificate + */ + result = setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY], va_arg(param, char *)); break; case CURLOPT_CAPATH: @@ -2103,7 +2228,20 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * certificates which have been prepared using openssl c_rehash utility. */ /* This does not work on windows. */ - result = setstropt(&data->set.str[STRING_SSL_CAPATH], + result = setstropt(&data->set.str[STRING_SSL_CAPATH_ORIG], + va_arg(param, char *)); +#else + result = CURLE_NOT_BUILT_IN; +#endif + break; + case CURLOPT_PROXY_CAPATH: +#ifdef have_curlssl_ca_path /* not supported by all backends */ + /* + * Set CA path info for SSL connection proxy. Specify directory name of the + * CA certificates which have been prepared using openssl c_rehash utility. + */ + /* This does not work on windows. */ + result = setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY], va_arg(param, char *)); #else result = CURLE_NOT_BUILT_IN; @@ -2114,7 +2252,15 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Set CRL file info for SSL connection. Specify file name of the CRL * to check certificates revocation */ - result = setstropt(&data->set.str[STRING_SSL_CRLFILE], + result = setstropt(&data->set.str[STRING_SSL_CRLFILE_ORIG], + va_arg(param, char *)); + break; + case CURLOPT_PROXY_CRLFILE: + /* + * Set CRL file info for SSL connection for proxy. Specify file name of the + * CRL to check certificates revocation + */ + result = setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY], va_arg(param, char *)); break; case CURLOPT_ISSUERCERT: @@ -2122,7 +2268,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Set Issuer certificate file * to check certificates issuer */ - result = setstropt(&data->set.str[STRING_SSL_ISSUERCERT], + result = setstropt(&data->set.str[STRING_SSL_ISSUERCERT_ORIG], va_arg(param, char *)); break; case CURLOPT_TELNETOPTIONS: @@ -2139,9 +2285,20 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ data->set.buffer_size = va_arg(param, long); - if((data->set.buffer_size> (BUFSIZE -1)) || - (data->set.buffer_size < 1)) - data->set.buffer_size = 0; /* huge internal default */ + if(data->set.buffer_size > MAX_BUFSIZE) + data->set.buffer_size = MAX_BUFSIZE; /* huge internal default */ + else if(data->set.buffer_size < 1) + data->set.buffer_size = BUFSIZE; + + /* Resize only if larger than default buffer size. */ + if(data->set.buffer_size > BUFSIZE) { + data->state.buffer = realloc(data->state.buffer, + data->set.buffer_size + 1); + if(!data->state.buffer) { + DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n")); + result = CURLE_OUT_OF_MEMORY; + } + } break; @@ -2203,7 +2360,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, } #endif /* CURL_DISABLE_HTTP */ if(data->share->sslsession) { - data->set.ssl.max_ssl_sessions = data->share->max_ssl_sessions; + data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions; data->state.session = data->share->sslsession; } Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); @@ -2238,8 +2395,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, case CURLOPT_SSL_OPTIONS: arg = va_arg(param, long); - data->set.ssl_enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST); - data->set.ssl_no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); + data->set.ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE; + data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); + break; + + case CURLOPT_PROXY_SSL_OPTIONS: + arg = va_arg(param, long); + data->set.proxy_ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE; + data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE); break; #endif @@ -2335,7 +2498,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_SSL_SESSIONID_CACHE: - data->set.ssl.sessionid = (0 != va_arg(param, long)) ? TRUE : FALSE; + data->set.general_ssl.sessionid = (0 != va_arg(param, long)) ? + TRUE : FALSE; break; #ifdef USE_LIBSSH2 @@ -2602,23 +2766,43 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; #ifdef USE_TLS_SRP case CURLOPT_TLSAUTH_USERNAME: - result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME], + result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_ORIG], va_arg(param, char *)); - if(data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype) + if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype) data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ break; + case CURLOPT_PROXY_TLSAUTH_USERNAME: + result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY], + va_arg(param, char *)); + if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] && + !data->set.proxy_ssl.authtype) + data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ + break; case CURLOPT_TLSAUTH_PASSWORD: - result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD], + result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_ORIG], va_arg(param, char *)); - if(data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype) + if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype) data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ break; + case CURLOPT_PROXY_TLSAUTH_PASSWORD: + result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY], + va_arg(param, char *)); + if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] && + !data->set.proxy_ssl.authtype) + data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */ + break; case CURLOPT_TLSAUTH_TYPE: - if(strnequal((char *)va_arg(param, char *), "SRP", strlen("SRP"))) + if(strncasecompare((char *)va_arg(param, char *), "SRP", strlen("SRP"))) data->set.ssl.authtype = CURL_TLSAUTH_SRP; else data->set.ssl.authtype = CURL_TLSAUTH_NONE; break; + case CURLOPT_PROXY_TLSAUTH_TYPE: + if(strncasecompare((char *)va_arg(param, char *), "SRP", strlen("SRP"))) + data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; + else + data->set.proxy_ssl.authtype = CURL_TLSAUTH_NONE; + break; #endif case CURLOPT_DNS_SERVERS: result = Curl_set_dns_servers(data, va_arg(param, char *)); @@ -2658,6 +2842,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, #ifdef USE_UNIX_SOCKETS case CURLOPT_UNIX_SOCKET_PATH: + data->set.abstract_unix_socket = FALSE; + result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], + va_arg(param, char *)); + break; + case CURLOPT_ABSTRACT_UNIX_SOCKET: + data->set.abstract_unix_socket = TRUE; result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], va_arg(param, char *)); break; @@ -2684,10 +2874,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, #ifndef USE_NGHTTP2 return CURLE_NOT_BUILT_IN; #else - struct SessionHandle *dep = va_arg(param, struct SessionHandle *); - if(dep && GOOD_EASY_HANDLE(dep)) { - data->set.stream_depends_on = dep; - data->set.stream_depends_e = (option == CURLOPT_STREAM_DEPENDS_E); + struct Curl_easy *dep = va_arg(param, struct Curl_easy *); + if(!dep || GOOD_EASY_HANDLE(dep)) { + if(data->set.stream_depends_on) { + Curl_http2_remove_child(data->set.stream_depends_on, data); + } + Curl_http2_add_child(dep, data, (option == CURLOPT_STREAM_DEPENDS_E)); } break; #endif @@ -2725,10 +2917,10 @@ static void conn_reset_postponed_data(struct connectdata *conn, int num) #endif /* DEBUGBUILD */ } else { - DEBUGASSERT (psnd->allocated_size == 0); - DEBUGASSERT (psnd->recv_size == 0); - DEBUGASSERT (psnd->recv_processed == 0); - DEBUGASSERT (psnd->bindsock == CURL_SOCKET_BAD); + DEBUGASSERT(psnd->allocated_size == 0); + DEBUGASSERT(psnd->recv_size == 0); + DEBUGASSERT(psnd->recv_processed == 0); + DEBUGASSERT(psnd->bindsock == CURL_SOCKET_BAD); } } @@ -2775,8 +2967,10 @@ static void conn_free(struct connectdata *conn) Curl_safefree(conn->passwd); Curl_safefree(conn->oauth_bearer); Curl_safefree(conn->options); - Curl_safefree(conn->proxyuser); - Curl_safefree(conn->proxypasswd); + Curl_safefree(conn->http_proxy.user); + Curl_safefree(conn->socks_proxy.user); + Curl_safefree(conn->http_proxy.passwd); + Curl_safefree(conn->socks_proxy.passwd); Curl_safefree(conn->allocptr.proxyuserpwd); Curl_safefree(conn->allocptr.uagent); Curl_safefree(conn->allocptr.userpwd); @@ -2790,7 +2984,9 @@ static void conn_free(struct connectdata *conn) Curl_safefree(conn->trailer); Curl_safefree(conn->host.rawalloc); /* host name buffer */ Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */ - Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */ + Curl_safefree(conn->secondaryhostname); + Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */ + Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */ Curl_safefree(conn->master_buffer); conn_reset_all_postponed_data(conn); @@ -2802,7 +2998,12 @@ static void conn_free(struct connectdata *conn) conn->recv_pipe = NULL; Curl_safefree(conn->localdev); - Curl_free_ssl_config(&conn->ssl_config); + Curl_free_primary_ssl_config(&conn->ssl_config); + Curl_free_primary_ssl_config(&conn->proxy_ssl_config); + +#ifdef USE_UNIX_SOCKETS + Curl_safefree(conn->unix_domain_socket); +#endif free(conn); /* free all the connection oriented data */ } @@ -2812,14 +3013,14 @@ static void conn_free(struct connectdata *conn) * primary connection, like when freeing room in the connection cache or * killing of a dead old connection. * - * This function MUST NOT reset state in the SessionHandle struct if that + * This function MUST NOT reset state in the Curl_easy struct if that * isn't strictly bound to the life-time of *this* particular connection. * */ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) { - struct SessionHandle *data; + struct Curl_easy *data; if(!conn) return CURLE_OK; /* this is closed and fine already */ data = conn->data; @@ -2829,6 +3030,17 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) return CURLE_OK; } + /* + * If this connection isn't marked to force-close, leave it open if there + * are other users of it + */ + if(!conn->bits.close && + (conn->send_pipe->size + conn->recv_pipe->size)) { + DEBUGF(infof(data, "Curl_disconnect, usecounter: %d\n", + conn->send_pipe->size + conn->recv_pipe->size)); + return CURLE_OK; + } + if(conn->dns_entry != NULL) { Curl_resolv_unlock(data, conn->dns_entry); conn->dns_entry = NULL; @@ -2851,7 +3063,8 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) free_fixed_hostname(&conn->host); free_fixed_hostname(&conn->conn_to_host); - free_fixed_hostname(&conn->proxy); + free_fixed_hostname(&conn->http_proxy.host); + free_fixed_hostname(&conn->socks_proxy.host); Curl_ssl_close(conn, FIRSTSOCKET); @@ -2876,7 +3089,7 @@ static bool SocketIsDead(curl_socket_t sock) int sval; bool ret_val = TRUE; - sval = Curl_socket_ready(sock, CURL_SOCKET_BAD, 0); + sval = SOCKET_READABLE(sock, 0); if(sval == 0) /* timeout */ ret_val = FALSE; @@ -2888,11 +3101,12 @@ static bool SocketIsDead(curl_socket_t sock) * IsPipeliningPossible() returns TRUE if the options set would allow * pipelining/multiplexing and the connection is using a HTTP protocol. */ -static bool IsPipeliningPossible(const struct SessionHandle *handle, +static bool IsPipeliningPossible(const struct Curl_easy *handle, const struct connectdata *conn) { /* If a HTTP protocol and pipelining is enabled */ - if(conn->handler->protocol & PROTO_FAMILY_HTTP) { + if((conn->handler->protocol & PROTO_FAMILY_HTTP) && + (!conn->bits.protoconnstart || !conn->bits.close)) { if(Curl_pipeline_wanted(handle->multi, CURLPIPE_HTTP1) && (handle->set.httpversion != CURL_HTTP_VERSION_1_0) && @@ -2909,7 +3123,7 @@ static bool IsPipeliningPossible(const struct SessionHandle *handle, return FALSE; } -int Curl_removeHandleFromPipeline(struct SessionHandle *handle, +int Curl_removeHandleFromPipeline(struct Curl_easy *handle, struct curl_llist *pipeline) { if(pipeline) { @@ -2935,18 +3149,18 @@ static void Curl_printPipeline(struct curl_llist *pipeline) curr = pipeline->head; while(curr) { - struct SessionHandle *data = (struct SessionHandle *) curr->ptr; + struct Curl_easy *data = (struct Curl_easy *) curr->ptr; infof(data, "Handle in pipeline: %s\n", data->state.path); curr = curr->next; } } #endif -static struct SessionHandle* gethandleathead(struct curl_llist *pipeline) +static struct Curl_easy* gethandleathead(struct curl_llist *pipeline) { struct curl_llist_element *curr = pipeline->head; if(curr) { - return (struct SessionHandle *) curr->ptr; + return (struct Curl_easy *) curr->ptr; } return NULL; @@ -2954,7 +3168,7 @@ static struct SessionHandle* gethandleathead(struct curl_llist *pipeline) /* remove the specified connection from all (possible) pipelines and related queues */ -void Curl_getoff_all_pipelines(struct SessionHandle *data, +void Curl_getoff_all_pipelines(struct Curl_easy *data, struct connectdata *conn) { bool recv_head = (conn->readchannel_inuse && @@ -2978,7 +3192,7 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke) curr = pipeline->head; while(curr) { struct curl_llist_element *next = curr->next; - struct SessionHandle *data = (struct SessionHandle *) curr->ptr; + struct Curl_easy *data = (struct Curl_easy *) curr->ptr; #ifdef DEBUGBUILD /* debug-only code */ if(data->magic != CURLEASY_MAGIC_NUMBER) { @@ -3003,14 +3217,14 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke) * found. */ struct connectdata * -Curl_oldest_idle_connection(struct SessionHandle *data) +Curl_oldest_idle_connection(struct Curl_easy *data) { struct conncache *bc = data->state.conn_cache; struct curl_hash_iterator iter; struct curl_llist_element *curr; struct curl_hash_element *he; - long highscore=-1; - long score; + time_t highscore=-1; + time_t score; struct timeval now; struct connectdata *conn_candidate = NULL; struct connectbundle *bundle; @@ -3047,6 +3261,21 @@ Curl_oldest_idle_connection(struct SessionHandle *data) return conn_candidate; } +static bool +proxy_info_matches(const struct proxy_info* data, + const struct proxy_info* needle) +{ + if((data->proxytype == needle->proxytype) && + (data->port == needle->port) && + Curl_safe_strcasecompare(data->host.name, needle->host.name) && + Curl_safe_strcasecompare(data->user, needle->user) && + Curl_safe_strcasecompare(data->passwd, needle->passwd)) + return TRUE; + + return FALSE; +} + + /* * This function finds the connection in the connection * bundle that has been unused for the longest time. @@ -3055,12 +3284,12 @@ Curl_oldest_idle_connection(struct SessionHandle *data) * found. */ static struct connectdata * -find_oldest_idle_connection_in_bundle(struct SessionHandle *data, +find_oldest_idle_connection_in_bundle(struct Curl_easy *data, struct connectbundle *bundle) { struct curl_llist_element *curr; - long highscore=-1; - long score; + time_t highscore=-1; + time_t score; struct timeval now; struct connectdata *conn_candidate = NULL; struct connectdata *conn; @@ -3095,7 +3324,7 @@ find_oldest_idle_connection_in_bundle(struct SessionHandle *data, * Returns TRUE if the connection actually was dead and disconnected. */ static bool disconnect_if_dead(struct connectdata *conn, - struct SessionHandle *data) + struct Curl_easy *data) { size_t pipeLen = conn->send_pipe->size + conn->recv_pipe->size; if(!pipeLen && !conn->inuse) { @@ -3129,7 +3358,7 @@ static bool disconnect_if_dead(struct connectdata *conn, static int call_disconnect_if_dead(struct connectdata *conn, void *param) { - struct SessionHandle* data = (struct SessionHandle*)param; + struct Curl_easy* data = (struct Curl_easy*)param; disconnect_if_dead(conn, data); return 0; /* continue iteration */ } @@ -3139,10 +3368,10 @@ static int call_disconnect_if_dead(struct connectdata *conn, * closes and removes them. * The cleanup is done at most once per second. */ -static void prune_dead_connections(struct SessionHandle *data) +static void prune_dead_connections(struct Curl_easy *data) { struct timeval now = Curl_tvnow(); - long elapsed = Curl_tvdiff(now, data->state.conn_cache->last_cleanup); + time_t elapsed = Curl_tvdiff(now, data->state.conn_cache->last_cleanup); if(elapsed >= 1000L) { Curl_conncache_foreach(data->state.conn_cache, data, @@ -3171,7 +3400,7 @@ static size_t max_pipeline_length(struct Curl_multi *multi) * the pipelining strategy wants to open a new connection instead of reusing. */ static bool -ConnectionExists(struct SessionHandle *data, +ConnectionExists(struct Curl_easy *data, struct connectdata *needle, struct connectdata **usethis, bool *force_reuse, @@ -3210,19 +3439,14 @@ ConnectionExists(struct SessionHandle *data, max_pipeline_length(data->multi):0; size_t best_pipe_len = max_pipe_len; struct curl_llist_element *curr; - const char *hostname; - - if(needle->bits.conn_to_host) - hostname = needle->conn_to_host.name; - else - hostname = needle->host.name; infof(data, "Found bundle for host %s: %p [%s]\n", - hostname, (void *)bundle, - (bundle->multiuse== BUNDLE_PIPELINING? - "can pipeline": - (bundle->multiuse== BUNDLE_MULTIPLEX? - "can multiplex":"serially"))); + (needle->bits.conn_to_host ? needle->conn_to_host.name : + needle->host.name), (void *)bundle, + (bundle->multiuse == BUNDLE_PIPELINING ? + "can pipeline" : + (bundle->multiuse == BUNDLE_MULTIPLEX ? + "can multiplex" : "serially"))); /* We can't pipe if we don't know anything about the server */ if(canPipeline) { @@ -3267,11 +3491,13 @@ ConnectionExists(struct SessionHandle *data, pipeLen = check->send_pipe->size + check->recv_pipe->size; if(canPipeline) { + if(check->bits.protoconnstart && check->bits.close) + continue; if(!check->bits.multiplex) { /* If not multiplexing, make sure the pipe has only GET requests */ - struct SessionHandle* sh = gethandleathead(check->send_pipe); - struct SessionHandle* rh = gethandleathead(check->recv_pipe); + struct Curl_easy* sh = gethandleathead(check->send_pipe); + struct Curl_easy* rh = gethandleathead(check->recv_pipe); if(sh) { if(!IsPipeliningPossible(sh, check)) continue; @@ -3319,6 +3545,19 @@ ConnectionExists(struct SessionHandle *data, } } +#ifdef USE_UNIX_SOCKETS + if(needle->unix_domain_socket) { + if(!check->unix_domain_socket) + continue; + if(strcmp(needle->unix_domain_socket, check->unix_domain_socket)) + continue; + if(needle->abstract_unix_socket != check->abstract_unix_socket) + continue; + } + else if(check->unix_domain_socket) + continue; +#endif + if((needle->handler->flags&PROTOPT_SSL) != (check->handler->flags&PROTOPT_SSL)) /* don't do mixed SSL and non-SSL connections */ @@ -3327,23 +3566,12 @@ ConnectionExists(struct SessionHandle *data, /* except protocols that have been upgraded via TLS */ continue; - if(needle->handler->flags&PROTOPT_SSL) { - if((data->set.ssl.verifypeer != check->verifypeer) || - (data->set.ssl.verifyhost != check->verifyhost)) - continue; - } - - if(needle->bits.proxy != check->bits.proxy) - /* don't do mixed proxy and non-proxy connections */ + if(needle->bits.httpproxy != check->bits.httpproxy || + needle->bits.socksproxy != check->bits.socksproxy) continue; - if(needle->bits.proxy && - (needle->proxytype != check->proxytype || - needle->bits.httpproxy != check->bits.httpproxy || - needle->bits.tunnel_proxy != check->bits.tunnel_proxy || - !Curl_raw_equal(needle->proxy.name, check->proxy.name) || - needle->port != check->port)) - /* don't mix connections that use different proxies */ + if(needle->bits.socksproxy && !proxy_info_matches(&needle->socks_proxy, + &check->socks_proxy)) continue; if(needle->bits.conn_to_host != check->bits.conn_to_host) @@ -3356,6 +3584,33 @@ ConnectionExists(struct SessionHandle *data, * connections that don't use this feature */ continue; + if(needle->bits.httpproxy) { + if(!proxy_info_matches(&needle->http_proxy, &check->http_proxy)) + continue; + + if(needle->bits.tunnel_proxy != check->bits.tunnel_proxy) + continue; + + if(needle->http_proxy.proxytype == CURLPROXY_HTTPS) { + /* use https proxy */ + if(needle->handler->flags&PROTOPT_SSL) { + /* use double layer ssl */ + if(!Curl_ssl_config_matches(&needle->proxy_ssl_config, + &check->proxy_ssl_config)) + continue; + if(check->proxy_ssl[FIRSTSOCKET].state != ssl_connection_complete) + continue; + } + else { + if(!Curl_ssl_config_matches(&needle->ssl_config, + &check->ssl_config)) + continue; + if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) + continue; + } + } + } + if(!canPipeline && check->inuse) /* this request can't be pipelined but the checked connection is already in use so we skip it */ @@ -3375,35 +3630,35 @@ ConnectionExists(struct SessionHandle *data, */ if((check->localport != needle->localport) || (check->localportrange != needle->localportrange) || - !check->localdev || - !needle->localdev || - strcmp(check->localdev, needle->localdev)) + (needle->localdev && + (!check->localdev || strcmp(check->localdev, needle->localdev)))) continue; } if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) { /* This protocol requires credentials per connection, so verify that we're using the same name and password as well */ - if(!strequal(needle->user, check->user) || - !strequal(needle->passwd, check->passwd)) { + if(strcmp(needle->user, check->user) || + strcmp(needle->passwd, check->passwd)) { /* one of them was different */ continue; } } if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) || - (needle->bits.httpproxy && needle->bits.tunnel_proxy)) { + needle->bits.tunnel_proxy) { /* The requested connection does not use a HTTP proxy or it uses SSL or - it is a non-SSL protocol tunneled over the same HTTP proxy name and - port number */ - if((Curl_raw_equal(needle->handler->scheme, check->handler->scheme) || + it is a non-SSL protocol tunneled or it is a non-SSL protocol which + is allowed to be upgraded via TLS */ + + if((strcasecompare(needle->handler->scheme, check->handler->scheme) || (get_protocol_family(check->handler->protocol) == needle->handler->protocol && check->tls_upgraded)) && - (!needle->bits.conn_to_host || Curl_raw_equal( + (!needle->bits.conn_to_host || strcasecompare( needle->conn_to_host.name, check->conn_to_host.name)) && (!needle->bits.conn_to_port || needle->conn_to_port == check->conn_to_port) && - Curl_raw_equal(needle->host.name, check->host.name) && + strcasecompare(needle->host.name, check->host.name) && needle->remote_port == check->remote_port) { /* The schemes match or the the protocol family is the same and the previous connection was TLS upgraded, and the hostname and host @@ -3445,8 +3700,8 @@ ConnectionExists(struct SessionHandle *data, possible. (Especially we must not reuse the same connection if partway through a handshake!) */ if(wantNTLMhttp) { - if(!strequal(needle->user, check->user) || - !strequal(needle->passwd, check->passwd)) + if(strcmp(needle->user, check->user) || + strcmp(needle->passwd, check->passwd)) continue; } else if(check->ntlm.state != NTLMSTATE_NONE) { @@ -3456,12 +3711,13 @@ ConnectionExists(struct SessionHandle *data, /* Same for Proxy NTLM authentication */ if(wantProxyNTLMhttp) { - /* Both check->proxyuser and check->proxypasswd can be NULL */ - if(!check->proxyuser || !check->proxypasswd) + /* Both check->http_proxy.user and check->http_proxy.passwd can be + * NULL */ + if(!check->http_proxy.user || !check->http_proxy.passwd) continue; - if(!strequal(needle->proxyuser, check->proxyuser) || - !strequal(needle->proxypasswd, check->proxypasswd)) + if(strcmp(needle->http_proxy.user, check->http_proxy.user) || + strcmp(needle->http_proxy.passwd, check->http_proxy.passwd)) continue; } else if(check->proxyntlm.state != NTLMSTATE_NONE) { @@ -3565,51 +3821,50 @@ ConnectionExists(struct SessionHandle *data, Note: this function's sub-functions call failf() */ -CURLcode Curl_connected_proxy(struct connectdata *conn, - int sockindex) +CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex) { - if(!conn->bits.proxy || sockindex) - /* this magic only works for the primary socket as the secondary is used - for FTP only and it has FTP specific magic in ftp.c */ - return CURLE_OK; + CURLcode result = CURLE_OK; - switch(conn->proxytype) { + if(conn->bits.socksproxy) { #ifndef CURL_DISABLE_PROXY - case CURLPROXY_SOCKS5: - case CURLPROXY_SOCKS5_HOSTNAME: - return Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, - conn->bits.conn_to_host ? conn->conn_to_host.name : - conn->host.name, - conn->bits.conn_to_port ? conn->conn_to_port : - conn->remote_port, - FIRSTSOCKET, conn); + /* for the secondary socket (FTP), use the "connect to host" + * but ignore the "connect to port" (use the secondary port) + */ + const char * const host = conn->bits.httpproxy ? + conn->http_proxy.host.name : + conn->bits.conn_to_host ? + conn->conn_to_host.name : + sockindex == SECONDARYSOCKET ? + conn->secondaryhostname : conn->host.name; + const int port = conn->bits.httpproxy ? (int)conn->http_proxy.port : + sockindex == SECONDARYSOCKET ? conn->secondary_port : + conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port; + conn->bits.socksproxy_connecting = TRUE; + switch(conn->socks_proxy.proxytype) { + case CURLPROXY_SOCKS5: + case CURLPROXY_SOCKS5_HOSTNAME: + result = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd, + host, port, sockindex, conn); + break; - case CURLPROXY_SOCKS4: - return Curl_SOCKS4(conn->proxyuser, - conn->bits.conn_to_host ? conn->conn_to_host.name : - conn->host.name, - conn->bits.conn_to_port ? conn->conn_to_port : - conn->remote_port, - FIRSTSOCKET, conn, FALSE); - - case CURLPROXY_SOCKS4A: - return Curl_SOCKS4(conn->proxyuser, - conn->bits.conn_to_host ? conn->conn_to_host.name : - conn->host.name, - conn->bits.conn_to_port ? conn->conn_to_port : - conn->remote_port, - FIRSTSOCKET, conn, TRUE); + case CURLPROXY_SOCKS4: + case CURLPROXY_SOCKS4A: + result = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex, + conn); + break; + default: + failf(conn->data, "unknown proxytype option given"); + result = CURLE_COULDNT_CONNECT; + } /* switch proxytype */ + conn->bits.socksproxy_connecting = FALSE; +#else + (void)sockindex; #endif /* CURL_DISABLE_PROXY */ - case CURLPROXY_HTTP: - case CURLPROXY_HTTP_1_0: - /* do nothing here. handled later. */ - break; - default: - break; - } /* switch proxytype */ + } - return CURLE_OK; + return result; } /* @@ -3620,7 +3875,10 @@ void Curl_verboseconnect(struct connectdata *conn) { if(conn->data->set.verbose) infof(conn->data, "Connected to %s (%s) port %ld (#%ld)\n", - conn->bits.proxy ? conn->proxy.dispname : conn->host.dispname, + conn->bits.socksproxy ? conn->socks_proxy.host.dispname : + conn->bits.httpproxy ? conn->http_proxy.host.dispname : + conn->bits.conn_to_host ? conn->conn_to_host.dispname : + conn->host.dispname, conn->ip_addr_str, conn->port, conn->connection_id); } #endif @@ -3710,10 +3968,14 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, if(!conn->bits.protoconnstart) { - result = Curl_proxy_connect(conn); + result = Curl_proxy_connect(conn, FIRSTSOCKET); if(result) return result; + if(CONNECT_FIRSTSOCKET_PROXY_SSL()) + /* wait for HTTPS proxy SSL initialization to complete */ + return CURLE_OK; + if(conn->bits.tunnel_proxy && conn->bits.httpproxy && (conn->tunnel_state[FIRSTSOCKET] != TUNNEL_COMPLETE)) /* when using an HTTP tunnel proxy, await complete tunnel establishment @@ -3743,7 +4005,7 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, */ static bool is_ASCII_name(const char *hostname) { - const unsigned char *ch = (const unsigned char*)hostname; + const unsigned char *ch = (const unsigned char *)hostname; while(*ch) { if(*ch++ & 0x80) @@ -3752,58 +4014,15 @@ static bool is_ASCII_name(const char *hostname) return TRUE; } -#ifdef USE_LIBIDN -/* - * Check if characters in hostname is allowed in Top Level Domain. - */ -static bool tld_check_name(struct SessionHandle *data, - const char *ace_hostname) -{ - size_t err_pos; - char *uc_name = NULL; - int rc; -#ifndef CURL_DISABLE_VERBOSE_STRINGS - const char *tld_errmsg = ""; -#else - (void)data; -#endif - - /* Convert (and downcase) ACE-name back into locale's character set */ - rc = idna_to_unicode_lzlz(ace_hostname, &uc_name, 0); - if(rc != IDNA_SUCCESS) - return FALSE; - - /* Warning: err_pos receives "the decoded character offset rather than the - byte position in the string." And as of libidn 1.32 that character offset - is for UTF-8, even if the passed in string is another locale. */ - rc = tld_check_lz(uc_name, &err_pos, NULL); -#ifndef CURL_DISABLE_VERBOSE_STRINGS -#ifdef HAVE_TLD_STRERROR - if(rc != TLD_SUCCESS) - tld_errmsg = tld_strerror((Tld_rc)rc); -#endif - if(rc != TLD_SUCCESS) - infof(data, "WARNING: TLD check for %s failed; %s\n", - uc_name, tld_errmsg); -#endif /* CURL_DISABLE_VERBOSE_STRINGS */ - if(uc_name) - idn_free(uc_name); - if(rc != TLD_SUCCESS) - return FALSE; - - return TRUE; -} -#endif - /* * Perform any necessary IDN conversion of hostname */ -static void fix_hostname(struct SessionHandle *data, - struct connectdata *conn, struct hostname *host) +static void fix_hostname(struct connectdata *conn, struct hostname *host) { size_t len; + struct Curl_easy *data = conn->data; -#ifndef USE_LIBIDN +#ifndef USE_LIBIDN2 (void)data; (void)conn; #elif defined(CURL_DISABLE_VERBOSE_STRINGS) @@ -3821,25 +4040,26 @@ static void fix_hostname(struct SessionHandle *data, /* Check name for non-ASCII and convert hostname to ACE form if we can */ if(!is_ASCII_name(host->name)) { -#ifdef USE_LIBIDN - if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) { +#ifdef USE_LIBIDN2 + if(idn2_check_version(IDN2_VERSION)) { char *ace_hostname = NULL; - - int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0); - infof(data, "Input domain encoded as `%s'\n", - stringprep_locale_charset()); - if(rc == IDNA_SUCCESS) { - /* tld_check_name() displays a warning if the host name contains - "illegal" characters for this TLD */ - (void)tld_check_name(data, ace_hostname); - - host->encalloc = ace_hostname; +#if IDN2_VERSION_NUMBER >= 0x00140000 + /* IDN2_NFC_INPUT: Normalize input string using normalization form C. + IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional + processing. */ + int flags = IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL; +#else + int flags = IDN2_NFC_INPUT; +#endif + int rc = idn2_lookup_ul((const char *)host->name, &ace_hostname, flags); + if(rc == IDN2_OK) { + host->encalloc = (char *)ace_hostname; /* change the name pointer to point to the encoded hostname */ host->name = host->encalloc; } else infof(data, "Failed to convert %s to ACE; %s\n", host->name, - Curl_idn_strerror(conn, rc)); + idn2_strerror(rc)); } #elif defined(USE_WIN32_IDN) char *ace_hostname = NULL; @@ -3862,9 +4082,9 @@ static void fix_hostname(struct SessionHandle *data, */ static void free_fixed_hostname(struct hostname *host) { -#if defined(USE_LIBIDN) +#if defined(USE_LIBIDN2) if(host->encalloc) { - idn_free(host->encalloc); /* must be freed with idn_free() since this was + idn2_free(host->encalloc); /* must be freed with idn2_free() since this was allocated by libidn */ host->encalloc = NULL; } @@ -3887,7 +4107,7 @@ static void llist_dtor(void *user, void *element) /* * Allocate and initialize a new connectdata object. */ -static struct connectdata *allocate_conn(struct SessionHandle *data) +static struct connectdata *allocate_conn(struct Curl_easy *data) { struct connectdata *conn = calloc(1, sizeof(struct connectdata)); if(!conn) @@ -3905,7 +4125,7 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->tempsock[1] = CURL_SOCKET_BAD; /* no file descriptor */ conn->connection_id = -1; /* no ID */ conn->port = -1; /* unknown at this point */ - conn->remote_port = -1; /* unknown */ + conn->remote_port = -1; /* unknown at this point */ #if defined(USE_RECV_BEFORE_SEND_WORKAROUND) && defined(DEBUGBUILD) conn->postponed[0].bindsock = CURL_SOCKET_BAD; /* no file descriptor */ conn->postponed[1].bindsock = CURL_SOCKET_BAD; /* no file descriptor */ @@ -3920,14 +4140,16 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->created = Curl_tvnow(); conn->data = data; /* Setup the association between this connection - and the SessionHandle */ + and the Curl_easy */ - conn->proxytype = data->set.proxytype; /* type */ + conn->http_proxy.proxytype = data->set.proxytype; + conn->socks_proxy.proxytype = CURLPROXY_SOCKS4; #ifdef CURL_DISABLE_PROXY conn->bits.proxy = FALSE; conn->bits.httpproxy = FALSE; + conn->bits.socksproxy = FALSE; conn->bits.proxy_user_passwd = FALSE; conn->bits.tunnel_proxy = FALSE; @@ -3938,11 +4160,20 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->bits.proxy = (data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]) ? TRUE : FALSE; conn->bits.httpproxy = (conn->bits.proxy && - (conn->proxytype == CURLPROXY_HTTP || - conn->proxytype == CURLPROXY_HTTP_1_0)) ? - TRUE : FALSE; - conn->bits.proxy_user_passwd = (data->set.str[STRING_PROXYUSERNAME]) ? - TRUE : FALSE; + (conn->http_proxy.proxytype == CURLPROXY_HTTP || + conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 || + conn->http_proxy.proxytype == CURLPROXY_HTTPS)) ? + TRUE : FALSE; + conn->bits.socksproxy = (conn->bits.proxy && + !conn->bits.httpproxy) ? TRUE : FALSE; + + if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) { + conn->bits.proxy = TRUE; + conn->bits.socksproxy = TRUE; + } + + conn->bits.proxy_user_passwd = + (data->set.str[STRING_PROXYUSERNAME]) ? TRUE : FALSE; conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy; #endif /* CURL_DISABLE_PROXY */ @@ -3951,8 +4182,13 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; - conn->verifypeer = data->set.ssl.verifypeer; - conn->verifyhost = data->set.ssl.verifyhost; + conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus; + conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer; + conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost; + conn->proxy_ssl_config.verifystatus = + data->set.proxy_ssl.primary.verifystatus; + conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer; + conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost; conn->ip_version = data->set.ipver; @@ -3967,7 +4203,7 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) if(Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1) && !conn->master_buffer) { /* Allocate master_buffer to be used for HTTP/1 pipelining */ - conn->master_buffer = calloc(BUFSIZE, sizeof (char)); + conn->master_buffer = calloc(BUFSIZE, sizeof(char)); if(!conn->master_buffer) goto error; } @@ -3992,7 +4228,7 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->localport = data->set.localport; /* the close socket stuff needs to be copied to the connection struct as - it may live on without (this specific) SessionHandle */ + it may live on without (this specific) Curl_easy */ conn->fclosesocket = data->set.fclosesocket; conn->closesocket_client = data->set.closesocket_client; @@ -4011,7 +4247,7 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) return NULL; } -static CURLcode findprotocol(struct SessionHandle *data, +static CURLcode findprotocol(struct Curl_easy *data, struct connectdata *conn, const char *protostr) { @@ -4022,7 +4258,7 @@ static CURLcode findprotocol(struct SessionHandle *data, variables based on the URL. Now that the handler may be changed later when the protocol specific setup function is called. */ for(pp = protocols; (p = *pp) != NULL; pp++) { - if(Curl_raw_equal(p->scheme, protostr)) { + if(strcasecompare(p->scheme, protostr)) { /* Protocol found in table. Check if allowed */ if(!(data->set.allowed_protocols & p->protocol)) /* nope, get out */ @@ -4056,7 +4292,7 @@ static CURLcode findprotocol(struct SessionHandle *data, /* * Parse URL and fill in the relevant members of the connection struct. */ -static CURLcode parseurlandfillconn(struct SessionHandle *data, +static CURLcode parseurlandfillconn(struct Curl_easy *data, struct connectdata *conn, bool *prot_missing, char **userp, char **passwdp, @@ -4066,11 +4302,13 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, char *fragment; char *path = data->state.path; char *query; + int i; int rc; - char protobuf[16] = ""; const char *protop = ""; CURLcode result; bool rebuild_url = FALSE; + bool url_has_scheme = FALSE; + char protobuf[16]; *prot_missing = FALSE; @@ -4089,10 +4327,47 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, * proxy -- and we don't know if we will need to use SSL until we parse the * url ... ************************************************************/ - if((2 == sscanf(data->change.url, "%15[^:]:%[^\n]", - protobuf, path)) && - Curl_raw_equal(protobuf, "file")) { - if(path[0] == '/' && path[1] == '/') { + if(data->change.url[0] == ':') { + failf(data, "Bad URL, colon is first character"); + return CURLE_URL_MALFORMAT; + } + + /* Make sure we don't mistake a drive letter for a scheme, for example: + curld --proto-default file c:/foo/bar.txt */ + if((('a' <= data->change.url[0] && data->change.url[0] <= 'z') || + ('A' <= data->change.url[0] && data->change.url[0] <= 'Z')) && + data->change.url[1] == ':' && data->set.str[STRING_DEFAULT_PROTOCOL] && + strcasecompare(data->set.str[STRING_DEFAULT_PROTOCOL], "file")) { + ; /* do nothing */ + } + else { /* check for a scheme */ + for(i = 0; i < 16 && data->change.url[i]; ++i) { + if(data->change.url[i] == '/') + break; + if(data->change.url[i] == ':') { + url_has_scheme = TRUE; + break; + } + } + } + + /* handle the file: scheme */ + if((url_has_scheme && strncasecompare(data->change.url, "file:", 5)) || + (!url_has_scheme && data->set.str[STRING_DEFAULT_PROTOCOL] && + strcasecompare(data->set.str[STRING_DEFAULT_PROTOCOL], "file"))) { + bool path_has_drive = FALSE; + + if(url_has_scheme) + rc = sscanf(data->change.url, "%*15[^\n/:]:%[^\n]", path); + else + rc = sscanf(data->change.url, "%[^\n]", path); + + if(rc != 1) { + failf(data, "Bad URL"); + return CURLE_URL_MALFORMAT; + } + + if(url_has_scheme && path[0] == '/' && path[1] == '/') { /* Allow omitted hostname (e.g. file:/). This is not strictly * speaking a valid file: URL by RFC 1738, but treating file:/ as * file://localhost/ is similar to how other schemes treat missing @@ -4102,57 +4377,84 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, memory areas overlap! */ memmove(path, path + 2, strlen(path + 2)+1); } + + /* the path may start with a drive letter. for backwards compatibility + we skip some processing on those paths. */ + path_has_drive = (('a' <= path[0] && path[0] <= 'z') || + ('A' <= path[0] && path[0] <= 'Z')) && path[1] == ':'; + /* * we deal with file:/// differently since it supports no * hostname other than "localhost" and "127.0.0.1", which is unique among * the URL protocols specified in RFC 1738 */ - if(path[0] != '/') { - /* the URL included a host name, we ignore host names in file:// URLs - as the standards don't define what to do with them */ - char *ptr=strchr(path, '/'); - if(ptr) { - /* there was a slash present - - RFC1738 (section 3.1, page 5) says: - - The rest of the locator consists of data specific to the scheme, - and is known as the "url-path". It supplies the details of how the - specified resource can be accessed. Note that the "/" between the - host (or port) and the url-path is NOT part of the url-path. - - As most agents use file://localhost/foo to get '/foo' although the - slash preceding foo is a separator and not a slash for the path, - a URL as file://localhost//foo must be valid as well, to refer to - the same file with an absolute path. - */ - - if(ptr[1] && ('/' == ptr[1])) - /* if there was two slashes, we skip the first one as that is then - used truly as a separator */ - ptr++; - - /* This cannot be made with strcpy, as the memory chunks overlap! */ - memmove(path, ptr, strlen(ptr)+1); + if(path[0] != '/' && !path_has_drive) { + /* the URL includes a host name, it must match "localhost" or + "127.0.0.1" to be valid */ + char *ptr; + if(!checkprefix("localhost/", path) && + !checkprefix("127.0.0.1/", path)) { + failf(data, "Invalid file://hostname/, " + "expected localhost or 127.0.0.1 or none"); + return CURLE_URL_MALFORMAT; } + ptr = &path[9]; /* now points to the slash after the host */ + + /* there was a host name and slash present + + RFC1738 (section 3.1, page 5) says: + + The rest of the locator consists of data specific to the scheme, + and is known as the "url-path". It supplies the details of how the + specified resource can be accessed. Note that the "/" between the + host (or port) and the url-path is NOT part of the url-path. + + As most agents use file://localhost/foo to get '/foo' although the + slash preceding foo is a separator and not a slash for the path, + a URL as file://localhost//foo must be valid as well, to refer to + the same file with an absolute path. + */ + + if('/' == ptr[1]) + /* if there was two slashes, we skip the first one as that is then + used truly as a separator */ + ptr++; + + /* This cannot be made with strcpy, as the memory chunks overlap! */ + memmove(path, ptr, strlen(ptr)+1); + + path_has_drive = (('a' <= path[0] && path[0] <= 'z') || + ('A' <= path[0] && path[0] <= 'Z')) && path[1] == ':'; } +#if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__) + if(path_has_drive) { + failf(data, "File drive letters are only accepted in MSDOS/Windows."); + return CURLE_URL_MALFORMAT; + } +#endif + protop = "file"; /* protocol string */ } else { /* clear path */ + char slashbuf[4]; path[0]=0; - if(2 > sscanf(data->change.url, - "%15[^\n:]://%[^\n/?]%[^\n]", - protobuf, - conn->host.name, path)) { + rc = sscanf(data->change.url, + "%15[^\n/:]:%3[/]%[^\n/?#]%[^\n]", + protobuf, slashbuf, conn->host.name, path); + if(2 == rc) { + failf(data, "Bad URL"); + return CURLE_URL_MALFORMAT; + } + if(3 > rc) { /* * The URL was badly formatted, let's try the browser-style _without_ * protocol specified like 'http://'. */ - rc = sscanf(data->change.url, "%[^\n/?]%[^\n]", conn->host.name, path); + rc = sscanf(data->change.url, "%[^\n/?#]%[^\n]", conn->host.name, path); if(1 > rc) { /* * We couldn't even get this format. @@ -4197,8 +4499,23 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, *prot_missing = TRUE; /* not given in URL */ } - else + else { + size_t s = strlen(slashbuf); protop = protobuf; + if(s != 2) { + infof(data, "Unwillingly accepted illegal URL using %d slash%s!\n", + s, s>1?"es":""); + + if(data->change.url_alloc) + free(data->change.url); + /* repair the URL to use two slashes */ + data->change.url = aprintf("%s://%s%s", + protobuf, conn->host.name, path); + if(!data->change.url) + return CURLE_OUT_OF_MEMORY; + data->change.url_alloc = TRUE; + } + } } /* We search for '?' in the host name (but only on the right side of a @@ -4242,10 +4559,10 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, } /* If the URL is malformatted (missing a '/' after hostname before path) we - * insert a slash here. The only letter except '/' we accept to start a path - * is '?'. + * insert a slash here. The only letters except '/' that can start a path is + * '?' and '#' - as controlled by the two sscanf() patterns above. */ - if(path[0] == '?') { + if(path[0] != '/') { /* We need this function to deal with overlapping memory areas. We know that the memory area 'path' points to is 'urllen' bytes big and that is bigger than the path. Use +1 to move the zero byte too. */ @@ -4310,6 +4627,10 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, data->change.url_alloc = TRUE; /* free this later */ } + result = findprotocol(data, conn, protop); + if(result) + return result; + /* * Parse the login details from the URL and strip them out of * the host name @@ -4396,15 +4717,14 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data, * conn->host.name is B * data->state.path is /C */ - - return findprotocol(data, conn, protop); + return CURLE_OK; } /* * If we're doing a resumed transfer, we need to setup our stuff * properly. */ -static CURLcode setup_range(struct SessionHandle *data) +static CURLcode setup_range(struct Curl_easy *data) { struct UrlState *s = &data->state; s->resume_from = data->set.set_resume_from; @@ -4436,7 +4756,7 @@ static CURLcode setup_range(struct SessionHandle *data) * setup_connection_internals() - * * Setup connection internals specific to the requested protocol in the - * SessionHandle. This is inited and setup before the connection is made but + * Curl_easy. This is inited and setup before the connection is made but * is about the particular protocol that is to be used. * * This MUST get called after proxy magic has been figured out. @@ -4445,7 +4765,7 @@ static CURLcode setup_connection_internals(struct connectdata *conn) { const struct Curl_handler * p; CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; /* in some case in the multi state-machine, we go back to the CONNECT state and then a second (or third or...) call to this function will be made @@ -4481,10 +4801,10 @@ static CURLcode setup_connection_internals(struct connectdata *conn) /* * Curl_free_request_state() should free temp data that was allocated in the - * SessionHandle for this single request. + * Curl_easy for this single request. */ -void Curl_free_request_state(struct SessionHandle *data) +void Curl_free_request_state(struct Curl_easy *data) { Curl_safefree(data->req.protop); Curl_safefree(data->req.newurl); @@ -4496,7 +4816,7 @@ void Curl_free_request_state(struct SessionHandle *data) * Checks if the host is in the noproxy list. returns true if it matches * and therefore the proxy should NOT be used. ****************************************************************/ -static bool check_noproxy(const char* name, const char* no_proxy) +static bool check_noproxy(const char *name, const char *no_proxy) { /* no_proxy=domain1.dom,host.domain2.dom * (a comma-separated list of hosts which should @@ -4505,13 +4825,13 @@ static bool check_noproxy(const char* name, const char* no_proxy) */ size_t tok_start; size_t tok_end; - const char* separator = ", "; + const char *separator = ", "; size_t no_proxy_len; size_t namelen; char *endptr; if(no_proxy && no_proxy[0]) { - if(Curl_raw_equal("*", no_proxy)) { + if(strcasecompare("*", no_proxy)) { return TRUE; } @@ -4549,7 +4869,7 @@ static bool check_noproxy(const char* name, const char* no_proxy) if((tok_end - tok_start) <= namelen) { /* Match the last part of the name to the domain we are checking. */ const char *checkn = name + namelen - (tok_end - tok_start); - if(Curl_raw_nequal(no_proxy + tok_start, checkn, + if(strncasecompare(no_proxy + tok_start, checkn, tok_end - tok_start)) { if((tok_end - tok_start) == namelen || *(checkn - 1) == '.') { /* We either have an exact match, or the previous character is a . @@ -4575,7 +4895,6 @@ static char *detect_proxy(struct connectdata *conn) { char *proxy = NULL; -#ifndef CURL_DISABLE_HTTP /* If proxy was not specified, we check for default proxy environment * variables, to enable i.e Lynx compliance: * @@ -4593,62 +4912,46 @@ static char *detect_proxy(struct connectdata *conn) * For compatibility, the all-uppercase versions of these variables are * checked if the lowercase versions don't exist. */ - char *no_proxy=NULL; char proxy_env[128]; + const char *protop = conn->handler->scheme; + char *envp = proxy_env; + char *prox; - no_proxy=curl_getenv("no_proxy"); - if(!no_proxy) - no_proxy=curl_getenv("NO_PROXY"); + /* Now, build _proxy and check for such a one to use */ + while(*protop) + *envp++ = (char)tolower((int)*protop++); - if(!check_noproxy(conn->host.name, no_proxy)) { - /* It was not listed as without proxy */ - const char *protop = conn->handler->scheme; - char *envp = proxy_env; - char *prox; + /* append _proxy */ + strcpy(envp, "_proxy"); - /* Now, build _proxy and check for such a one to use */ - while(*protop) - *envp++ = (char)tolower((int)*protop++); + /* read the protocol proxy: */ + prox=curl_getenv(proxy_env); - /* append _proxy */ - strcpy(envp, "_proxy"); - - /* read the protocol proxy: */ + /* + * We don't try the uppercase version of HTTP_PROXY because of + * security reasons: + * + * When curl is used in a webserver application + * environment (cgi or php), this environment variable can + * be controlled by the web server user by setting the + * http header 'Proxy:' to some value. + * + * This can cause 'internal' http/ftp requests to be + * arbitrarily redirected by any external attacker. + */ + if(!prox && !strcasecompare("http_proxy", proxy_env)) { + /* There was no lowercase variable, try the uppercase version: */ + Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env)); prox=curl_getenv(proxy_env); + } - /* - * We don't try the uppercase version of HTTP_PROXY because of - * security reasons: - * - * When curl is used in a webserver application - * environment (cgi or php), this environment variable can - * be controlled by the web server user by setting the - * http header 'Proxy:' to some value. - * - * This can cause 'internal' http/ftp requests to be - * arbitrarily redirected by any external attacker. - */ - if(!prox && !Curl_raw_equal("http_proxy", proxy_env)) { - /* There was no lowercase variable, try the uppercase version: */ - Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env)); - prox=curl_getenv(proxy_env); - } - - if(prox) - proxy = prox; /* use this */ - else { - proxy = curl_getenv("all_proxy"); /* default proxy to use */ - if(!proxy) - proxy=curl_getenv("ALL_PROXY"); - } - } /* if(!check_noproxy(conn->host.name, no_proxy)) - it wasn't specified - non-proxy */ - free(no_proxy); - -#else /* !CURL_DISABLE_HTTP */ - - (void)conn; -#endif /* CURL_DISABLE_HTTP */ + if(prox) + proxy = prox; /* use this */ + else { + proxy = curl_getenv("all_proxy"); /* default proxy to use */ + if(!proxy) + proxy=curl_getenv("ALL_PROXY"); + } return proxy; } @@ -4658,8 +4961,9 @@ static char *detect_proxy(struct connectdata *conn) * host name, so that we can re-use an existing connection * that may exist registered to the same proxy host. */ -static CURLcode parse_proxy(struct SessionHandle *data, - struct connectdata *conn, char *proxy) +static CURLcode parse_proxy(struct Curl_easy *data, + struct connectdata *conn, char *proxy, + curl_proxytype proxytype) { char *prox_portno; char *endofprot; @@ -4668,6 +4972,10 @@ static CURLcode parse_proxy(struct SessionHandle *data, char *proxyptr; char *portptr; char *atsign; + long port = -1; + char *proxyuser = NULL; + char *proxypasswd = NULL; + bool sockstype; /* We do the proxy host string parsing here. We want the host name and the * port name. Accept a protocol:// prefix @@ -4677,64 +4985,49 @@ static CURLcode parse_proxy(struct SessionHandle *data, endofprot = strstr(proxy, "://"); if(endofprot) { proxyptr = endofprot+3; - if(checkprefix("socks5h", proxy)) - conn->proxytype = CURLPROXY_SOCKS5_HOSTNAME; + if(checkprefix("https", proxy)) + proxytype = CURLPROXY_HTTPS; + else if(checkprefix("socks5h", proxy)) + proxytype = CURLPROXY_SOCKS5_HOSTNAME; else if(checkprefix("socks5", proxy)) - conn->proxytype = CURLPROXY_SOCKS5; + proxytype = CURLPROXY_SOCKS5; else if(checkprefix("socks4a", proxy)) - conn->proxytype = CURLPROXY_SOCKS4A; + proxytype = CURLPROXY_SOCKS4A; else if(checkprefix("socks4", proxy) || checkprefix("socks", proxy)) - conn->proxytype = CURLPROXY_SOCKS4; - /* Any other xxx:// : change to http proxy */ + proxytype = CURLPROXY_SOCKS4; + else if(checkprefix("http:", proxy)) + ; /* leave it as HTTP or HTTP/1.0 */ + else { + /* Any other xxx:// reject! */ + failf(data, "Unsupported proxy scheme for \'%s\'", proxy); + return CURLE_COULDNT_CONNECT; + } } else proxyptr = proxy; /* No xxx:// head: It's a HTTP proxy */ +#ifndef HTTPS_PROXY_SUPPORT + if(proxytype == CURLPROXY_HTTPS) { + failf(data, "Unsupported proxy \'%s\'" + ", libcurl is built without the HTTPS-proxy support.", proxy); + return CURLE_NOT_BUILT_IN; + } +#endif + + sockstype = proxytype == CURLPROXY_SOCKS5_HOSTNAME || + proxytype == CURLPROXY_SOCKS5 || + proxytype == CURLPROXY_SOCKS4A || + proxytype == CURLPROXY_SOCKS4; + /* Is there a username and password given in this proxy url? */ atsign = strchr(proxyptr, '@'); if(atsign) { - char *proxyuser = NULL; - char *proxypasswd = NULL; CURLcode result = parse_login_details(proxyptr, atsign - proxyptr, - &proxyuser, &proxypasswd, NULL); - if(!result) { - /* found user and password, rip them out. note that we are - unescaping them, as there is otherwise no way to have a - username or password with reserved characters like ':' in - them. */ - Curl_safefree(conn->proxyuser); - if(proxyuser && strlen(proxyuser) < MAX_CURL_USER_LENGTH) - conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); - else - conn->proxyuser = strdup(""); - - if(!conn->proxyuser) - result = CURLE_OUT_OF_MEMORY; - else { - Curl_safefree(conn->proxypasswd); - if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH) - conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); - else - conn->proxypasswd = strdup(""); - - if(!conn->proxypasswd) - result = CURLE_OUT_OF_MEMORY; - } - - if(!result) { - conn->bits.proxy_user_passwd = TRUE; /* enable it */ - atsign++; /* the right side of the @-letter */ - - proxyptr = atsign; /* now use this instead */ - } - } - - free(proxyuser); - free(proxypasswd); - + &proxyuser, &proxypasswd, NULL); if(result) return result; + proxyptr = atsign + 1; } /* start scanning for port number at this point */ @@ -4771,7 +5064,7 @@ static CURLcode parse_proxy(struct SessionHandle *data, prox_portno = strchr(portptr, ':'); if(prox_portno) { char *endp = NULL; - long port = 0; + *prox_portno = 0x0; /* cut off number from host name */ prox_portno ++; /* now set the local port number */ @@ -4805,15 +5098,59 @@ static CURLcode parse_proxy(struct SessionHandle *data, if(data->set.proxyport) /* None given in the proxy string, then get the default one if it is given */ - conn->port = data->set.proxyport; + port = data->set.proxyport; + else { + if(proxytype == CURLPROXY_HTTPS) + port = CURL_DEFAULT_HTTPS_PROXY_PORT; + else + port = CURL_DEFAULT_PROXY_PORT; + } } - /* now, clone the cleaned proxy host name */ - conn->proxy.rawalloc = strdup(proxyptr); - conn->proxy.name = conn->proxy.rawalloc; + if(*proxyptr) { + struct proxy_info *proxyinfo = + sockstype ? &conn->socks_proxy : &conn->http_proxy; + proxyinfo->proxytype = proxytype; - if(!conn->proxy.rawalloc) - return CURLE_OUT_OF_MEMORY; + if(proxyuser) { + /* found user and password, rip them out. note that we are unescaping + them, as there is otherwise no way to have a username or password + with reserved characters like ':' in them. */ + Curl_safefree(proxyinfo->user); + proxyinfo->user = curl_easy_unescape(data, proxyuser, 0, NULL); + + if(!proxyinfo->user) + return CURLE_OUT_OF_MEMORY; + + Curl_safefree(proxyinfo->passwd); + if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH) + proxyinfo->passwd = curl_easy_unescape(data, proxypasswd, 0, NULL); + else + proxyinfo->passwd = strdup(""); + + if(!proxyinfo->passwd) + return CURLE_OUT_OF_MEMORY; + + conn->bits.proxy_user_passwd = TRUE; /* enable it */ + } + + if(port >= 0) { + proxyinfo->port = port; + if(conn->port < 0 || sockstype || !conn->socks_proxy.host.rawalloc) + conn->port = port; + } + + /* now, clone the cleaned proxy host name */ + Curl_safefree(proxyinfo->host.rawalloc); + proxyinfo->host.rawalloc = strdup(proxyptr); + proxyinfo->host.name = proxyinfo->host.rawalloc; + + if(!proxyinfo->host.rawalloc) + return CURLE_OUT_OF_MEMORY; + } + + Curl_safefree(proxyuser); + Curl_safefree(proxypasswd); return CURLE_OK; } @@ -4821,11 +5158,12 @@ static CURLcode parse_proxy(struct SessionHandle *data, /* * Extract the user and password from the authentication string */ -static CURLcode parse_proxy_auth(struct SessionHandle *data, +static CURLcode parse_proxy_auth(struct Curl_easy *data, struct connectdata *conn) { char proxyuser[MAX_CURL_USER_LENGTH]=""; char proxypasswd[MAX_CURL_PASSWORD_LENGTH]=""; + CURLcode result; if(data->set.str[STRING_PROXYUSERNAME] != NULL) { strncpy(proxyuser, data->set.str[STRING_PROXYUSERNAME], @@ -4838,15 +5176,12 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data, proxypasswd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/ } - conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL); - if(!conn->proxyuser) - return CURLE_OUT_OF_MEMORY; - - conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL); - if(!conn->proxypasswd) - return CURLE_OUT_OF_MEMORY; - - return CURLE_OK; + result = Curl_urldecode(data, proxyuser, 0, &conn->http_proxy.user, NULL, + FALSE); + if(!result) + result = Curl_urldecode(data, proxypasswd, 0, &conn->http_proxy.passwd, + NULL, FALSE); + return result; } #endif /* CURL_DISABLE_PROXY */ @@ -4866,7 +5201,7 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data, * options - non-zero length if defined * conn->host.name - remove user name and password */ -static CURLcode parse_url_login(struct SessionHandle *data, +static CURLcode parse_url_login(struct Curl_easy *data, struct connectdata *conn, char **user, char **passwd, char **options) { @@ -4888,6 +5223,7 @@ static CURLcode parse_url_login(struct SessionHandle *data, DEBUGASSERT(!**user); DEBUGASSERT(!**passwd); DEBUGASSERT(!**options); + DEBUGASSERT(conn->handler); if(!ptr) goto out; @@ -4906,9 +5242,12 @@ static CURLcode parse_url_login(struct SessionHandle *data, if(data->set.use_netrc == CURL_NETRC_REQUIRED) goto out; - /* We could use the login information in the URL so extract it */ + /* We could use the login information in the URL so extract it. Only parse + options if the handler says we should. */ result = parse_login_details(login, ptr - login - 1, - &userp, &passwdp, &optionsp); + &userp, &passwdp, + (conn->handler->flags & PROTOPT_URLOPTIONS)? + &optionsp:NULL); if(result) goto out; @@ -4920,9 +5259,8 @@ static CURLcode parse_url_login(struct SessionHandle *data, conn->bits.user_passwd = TRUE; /* enable user+password */ /* Decode the user */ - newname = curl_easy_unescape(data, userp, 0, NULL); - if(!newname) { - result = CURLE_OUT_OF_MEMORY; + result = Curl_urldecode(data, userp, 0, &newname, NULL, FALSE); + if(result) { goto out; } @@ -4932,9 +5270,9 @@ static CURLcode parse_url_login(struct SessionHandle *data, if(passwdp) { /* We have a password in the URL so decode it */ - char *newpasswd = curl_easy_unescape(data, passwdp, 0, NULL); - if(!newpasswd) { - result = CURLE_OUT_OF_MEMORY; + char *newpasswd; + result = Curl_urldecode(data, passwdp, 0, &newpasswd, NULL, FALSE); + if(result) { goto out; } @@ -4944,9 +5282,9 @@ static CURLcode parse_url_login(struct SessionHandle *data, if(optionsp) { /* We have an options list in the URL so decode it */ - char *newoptions = curl_easy_unescape(data, optionsp, 0, NULL); - if(!newoptions) { - result = CURLE_OUT_OF_MEMORY; + char *newoptions; + result = Curl_urldecode(data, optionsp, 0, &newoptions, NULL, FALSE); + if(result) { goto out; } @@ -5105,7 +5443,7 @@ static CURLcode parse_login_details(const char *login, const size_t len, * * The port number embedded in the URL is replaced, if necessary. *************************************************************/ -static CURLcode parse_remote_port(struct SessionHandle *data, +static CURLcode parse_remote_port(struct Curl_easy *data, struct connectdata *conn) { char *portptr; @@ -5198,11 +5536,16 @@ static CURLcode parse_remote_port(struct SessionHandle *data, *portptr = '\0'; /* cut off the name there */ conn->remote_port = curlx_ultous(port); } - else + else { + if(rest[0]) { + failf(data, "Illegal port number"); + return CURLE_URL_MALFORMAT; + } /* Browser behavior adaptation. If there's a colon with no digits after, just cut off the name there which makes us ignore the colon and just use the default port. Firefox and Chrome both do that. */ *portptr = '\0'; + } } /* only if remote_port was not already parsed off the URL we use the @@ -5217,7 +5560,7 @@ static CURLcode parse_remote_port(struct SessionHandle *data, * Override the login details from the URL with that in the CURLOPT_USERPWD * option or a .netrc file, if applicable. */ -static CURLcode override_login(struct SessionHandle *data, +static CURLcode override_login(struct Curl_easy *data, struct connectdata *conn, char **userp, char **passwdp, char **optionsp) { @@ -5320,7 +5663,7 @@ static CURLcode set_login(struct connectdata *conn, * The hostname and the port may be empty; in this case, NULL is returned for * the hostname and -1 for the port. */ -static CURLcode parse_connect_to_host_port(struct SessionHandle *data, +static CURLcode parse_connect_to_host_port(struct Curl_easy *data, const char *host, char **hostname_result, int *port_result) @@ -5331,6 +5674,10 @@ static CURLcode parse_connect_to_host_port(struct SessionHandle *data, char *portptr; int port = -1; +#if defined(CURL_DISABLE_VERBOSE_STRINGS) + (void) data; +#endif + *hostname_result = NULL; *port_result = -1; @@ -5411,7 +5758,7 @@ static CURLcode parse_connect_to_host_port(struct SessionHandle *data, * Parses one "connect to" string in the form: * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT". */ -static CURLcode parse_connect_to_string(struct SessionHandle *data, +static CURLcode parse_connect_to_string(struct Curl_easy *data, struct connectdata *conn, const char *conn_to_host, char **host_result, @@ -5422,6 +5769,9 @@ static CURLcode parse_connect_to_string(struct SessionHandle *data, int host_match = FALSE; int port_match = FALSE; + *host_result = NULL; + *port_result = -1; + if(*ptr == ':') { /* an empty hostname always matches */ host_match = TRUE; @@ -5437,7 +5787,8 @@ static CURLcode parse_connect_to_string(struct SessionHandle *data, if(!hostname_to_match) return CURLE_OUT_OF_MEMORY; hostname_to_match_len = strlen(hostname_to_match); - host_match = curl_strnequal(ptr, hostname_to_match, hostname_to_match_len); + host_match = strncasecompare(ptr, hostname_to_match, + hostname_to_match_len); free(hostname_to_match); ptr += hostname_to_match_len; @@ -5477,34 +5828,31 @@ static CURLcode parse_connect_to_string(struct SessionHandle *data, * Processes all strings in the "connect to" slist, and uses the "connect * to host" and "connect to port" of the first string that matches. */ -static CURLcode parse_connect_to_slist(struct SessionHandle *data, +static CURLcode parse_connect_to_slist(struct Curl_easy *data, struct connectdata *conn, struct curl_slist *conn_to_host) { CURLcode result = CURLE_OK; char *host = NULL; - int port = 0; + int port = -1; - while(conn_to_host && !host) { + while(conn_to_host && !host && port == -1) { result = parse_connect_to_string(data, conn, conn_to_host->data, &host, &port); if(result) return result; if(host && *host) { - bool ipv6host; conn->conn_to_host.rawalloc = host; conn->conn_to_host.name = host; conn->bits.conn_to_host = TRUE; - ipv6host = strchr(host, ':') != NULL; - infof(data, "Connecting to hostname: %s%s%s\n", - ipv6host ? "[" : "", host, ipv6host ? "]" : ""); + infof(data, "Connecting to hostname: %s\n", host); } else { /* no "connect to host" */ conn->bits.conn_to_host = FALSE; - free(host); + Curl_safefree(host); } if(port >= 0) { @@ -5515,6 +5863,7 @@ static CURLcode parse_connect_to_slist(struct SessionHandle *data, else { /* no "connect to port" */ conn->bits.conn_to_port = FALSE; + port = -1; } conn_to_host = conn_to_host->next; @@ -5526,12 +5875,12 @@ static CURLcode parse_connect_to_slist(struct SessionHandle *data, /************************************************************* * Resolve the address of the server or proxy *************************************************************/ -static CURLcode resolve_server(struct SessionHandle *data, +static CURLcode resolve_server(struct Curl_easy *data, struct connectdata *conn, bool *async) { CURLcode result=CURLE_OK; - long timeout_ms = Curl_timeleft(data, NULL, TRUE); + time_t timeout_ms = Curl_timeleft(data, NULL, TRUE); /************************************************************* * Resolve the name of the server or proxy @@ -5548,32 +5897,37 @@ static CURLcode resolve_server(struct SessionHandle *data, struct Curl_dns_entry *hostaddr; #ifdef USE_UNIX_SOCKETS - if(data->set.str[STRING_UNIX_SOCKET_PATH]) { + if(conn->unix_domain_socket) { /* Unix domain sockets are local. The host gets ignored, just use the * specified domain socket address. Do not cache "DNS entries". There is * no DNS involved and we already have the filesystem path available */ - const char *path = data->set.str[STRING_UNIX_SOCKET_PATH]; + const char *path = conn->unix_domain_socket; hostaddr = calloc(1, sizeof(struct Curl_dns_entry)); if(!hostaddr) result = CURLE_OUT_OF_MEMORY; - else if((hostaddr->addr = Curl_unix2addr(path)) != NULL) - hostaddr->inuse++; else { - /* Long paths are not supported for now */ - if(strlen(path) >= sizeof(((struct sockaddr_un *)0)->sun_path)) { - failf(data, "Unix socket path too long: '%s'", path); - result = CURLE_COULDNT_RESOLVE_HOST; + bool longpath = FALSE; + hostaddr->addr = Curl_unix2addr(path, &longpath, + conn->abstract_unix_socket); + if(hostaddr->addr) + hostaddr->inuse++; + else { + /* Long paths are not supported for now */ + if(longpath) { + failf(data, "Unix socket path too long: '%s'", path); + result = CURLE_COULDNT_RESOLVE_HOST; + } + else + result = CURLE_OUT_OF_MEMORY; + free(hostaddr); + hostaddr = NULL; } - else - result = CURLE_OUT_OF_MEMORY; - free(hostaddr); - hostaddr = NULL; } } else #endif - if(!conn->proxy.name || !*conn->proxy.name) { + if(!conn->bits.proxy) { struct hostname *connhost; if(conn->bits.conn_to_host) connhost = &conn->conn_to_host; @@ -5585,7 +5939,7 @@ static CURLcode resolve_server(struct SessionHandle *data, if(conn->bits.conn_to_port) conn->port = conn->conn_to_port; else - conn->port = conn->remote_port; /* it is the same port */ + conn->port = conn->remote_port; /* Resolve target host right on */ rc = Curl_resolv_timeout(conn, connhost->name, (int)conn->port, @@ -5605,8 +5959,11 @@ static CURLcode resolve_server(struct SessionHandle *data, else { /* This is a proxy that hasn't been resolved yet. */ + struct hostname * const host = conn->bits.socksproxy ? + &conn->socks_proxy.host : &conn->http_proxy.host; + /* resolve proxy */ - rc = Curl_resolv_timeout(conn, conn->proxy.name, (int)conn->port, + rc = Curl_resolv_timeout(conn, host->name, (int)conn->port, &hostaddr, timeout_ms); if(rc == CURLRESOLV_PENDING) @@ -5616,7 +5973,7 @@ static CURLcode resolve_server(struct SessionHandle *data, result = CURLE_OPERATION_TIMEDOUT; else if(!hostaddr) { - failf(data, "Couldn't resolve proxy '%s'", conn->proxy.dispname); + failf(data, "Couldn't resolve proxy '%s'", host->dispname); result = CURLE_COULDNT_RESOLVE_PROXY; /* don't return yet, we need to clean up the timeout first */ } @@ -5636,12 +5993,16 @@ static CURLcode resolve_server(struct SessionHandle *data, static void reuse_conn(struct connectdata *old_conn, struct connectdata *conn) { - free_fixed_hostname(&old_conn->proxy); - free(old_conn->proxy.rawalloc); + free_fixed_hostname(&old_conn->http_proxy.host); + free_fixed_hostname(&old_conn->socks_proxy.host); + + free(old_conn->http_proxy.host.rawalloc); + free(old_conn->socks_proxy.host.rawalloc); /* free the SSL config struct from this connection struct as this was allocated in vain and is targeted for destruction */ - Curl_free_ssl_config(&old_conn->ssl_config); + Curl_free_primary_ssl_config(&old_conn->ssl_config); + Curl_free_primary_ssl_config(&old_conn->proxy_ssl_config); conn->data = old_conn->data; @@ -5661,12 +6022,18 @@ static void reuse_conn(struct connectdata *old_conn, conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd; if(conn->bits.proxy_user_passwd) { /* use the new proxy user name and proxy password though */ - Curl_safefree(conn->proxyuser); - Curl_safefree(conn->proxypasswd); - conn->proxyuser = old_conn->proxyuser; - conn->proxypasswd = old_conn->proxypasswd; - old_conn->proxyuser = NULL; - old_conn->proxypasswd = NULL; + Curl_safefree(conn->http_proxy.user); + Curl_safefree(conn->socks_proxy.user); + Curl_safefree(conn->http_proxy.passwd); + Curl_safefree(conn->socks_proxy.passwd); + conn->http_proxy.user = old_conn->http_proxy.user; + conn->socks_proxy.user = old_conn->socks_proxy.user; + conn->http_proxy.passwd = old_conn->http_proxy.passwd; + conn->socks_proxy.passwd = old_conn->socks_proxy.passwd; + old_conn->http_proxy.user = NULL; + old_conn->socks_proxy.user = NULL; + old_conn->http_proxy.passwd = NULL; + old_conn->socks_proxy.passwd = NULL; } /* host can change, when doing keepalive with a proxy or if the case is @@ -5692,8 +6059,10 @@ static void reuse_conn(struct connectdata *old_conn, Curl_safefree(old_conn->user); Curl_safefree(old_conn->passwd); - Curl_safefree(old_conn->proxyuser); - Curl_safefree(old_conn->proxypasswd); + Curl_safefree(old_conn->http_proxy.user); + Curl_safefree(old_conn->socks_proxy.user); + Curl_safefree(old_conn->http_proxy.passwd); + Curl_safefree(old_conn->socks_proxy.passwd); Curl_safefree(old_conn->localdev); Curl_llist_destroy(old_conn->send_pipe, NULL); @@ -5703,6 +6072,10 @@ static void reuse_conn(struct connectdata *old_conn, old_conn->recv_pipe = NULL; Curl_safefree(old_conn->master_buffer); + +#ifdef USE_UNIX_SOCKETS + Curl_safefree(old_conn->unix_domain_socket); +#endif } /** @@ -5721,7 +6094,7 @@ static void reuse_conn(struct connectdata *old_conn, * *NOTE* this function assigns the conn->data pointer! */ -static CURLcode create_conn(struct SessionHandle *data, +static CURLcode create_conn(struct Curl_easy *data, struct connectdata **in_connect, bool *async) { @@ -5734,6 +6107,8 @@ static CURLcode create_conn(struct SessionHandle *data, char *options = NULL; bool reuse; char *proxy = NULL; + char *socksproxy = NULL; + char *no_proxy = NULL; bool prot_missing = FALSE; bool connections_available = TRUE; bool force_reuse = FALSE; @@ -5900,18 +6275,48 @@ static CURLcode create_conn(struct SessionHandle *data, } } - if(data->set.str[STRING_NOPROXY] && - check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY])) { - free(proxy); /* proxy is in exception list */ - proxy = NULL; + if(data->set.str[STRING_PRE_PROXY]) { + socksproxy = strdup(data->set.str[STRING_PRE_PROXY]); + /* if global socks proxy is set, this is it */ + if(NULL == socksproxy) { + failf(data, "memory shortage"); + result = CURLE_OUT_OF_MEMORY; + goto out; + } } - else if(!proxy) + + no_proxy = curl_getenv("no_proxy"); + if(!no_proxy) + no_proxy = curl_getenv("NO_PROXY"); + + if(check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY]) || + (!data->set.str[STRING_NOPROXY] && + check_noproxy(conn->host.name, no_proxy))) { + Curl_safefree(proxy); + Curl_safefree(socksproxy); + } + else if(!proxy && !socksproxy) +#ifndef CURL_DISABLE_HTTP + /* if the host is not in the noproxy list, detect proxy. */ proxy = detect_proxy(conn); +#else /* !CURL_DISABLE_HTTP */ + proxy = NULL; +#endif /* CURL_DISABLE_HTTP */ + + Curl_safefree(no_proxy); #ifdef USE_UNIX_SOCKETS - if(proxy && data->set.str[STRING_UNIX_SOCKET_PATH]) { - free(proxy); /* Unix domain sockets cannot be proxied, so disable it */ - proxy = NULL; + if(data->set.str[STRING_UNIX_SOCKET_PATH]) { + if(proxy) { + free(proxy); /* Unix domain sockets cannot be proxied, so disable it */ + proxy = NULL; + } + conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]); + if(conn->unix_domain_socket == NULL) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + conn->abstract_unix_socket = data->set.abstract_unix_socket; } #endif @@ -5920,23 +6325,36 @@ static CURLcode create_conn(struct SessionHandle *data, protocol doesn't work with network */ proxy = NULL; } + if(socksproxy && (!*socksproxy || + (conn->handler->flags & PROTOPT_NONETWORK))) { + free(socksproxy); /* Don't bother with an empty socks proxy string or if + the protocol doesn't work with network */ + socksproxy = NULL; + } /*********************************************************************** * If this is supposed to use a proxy, we need to figure out the proxy host * name, proxy type and port number, so that we can re-use an existing * connection that may exist registered to the same proxy host. ***********************************************************************/ - if(proxy) { - result = parse_proxy(data, conn, proxy); + if(proxy || socksproxy) { + if(proxy) { + result = parse_proxy(data, conn, proxy, conn->http_proxy.proxytype); + Curl_safefree(proxy); /* parse_proxy copies the proxy string */ + if(result) + goto out; + } - free(proxy); /* parse_proxy copies the proxy string */ - proxy = NULL; + if(socksproxy) { + result = parse_proxy(data, conn, socksproxy, + conn->socks_proxy.proxytype); + /* parse_proxy copies the socks proxy string */ + Curl_safefree(socksproxy); + if(result) + goto out; + } - if(result) - goto out; - - if((conn->proxytype == CURLPROXY_HTTP) || - (conn->proxytype == CURLPROXY_HTTP_1_0)) { + if(conn->http_proxy.host.rawalloc) { #ifdef CURL_DISABLE_HTTP /* asking for a HTTP proxy is a bit funny when HTTP is disabled... */ result = CURLE_UNSUPPORTED_PROTOCOL; @@ -5955,12 +6373,34 @@ static CURLcode create_conn(struct SessionHandle *data, conn->bits.httpproxy = FALSE; /* not a HTTP proxy */ conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */ } - conn->bits.proxy = TRUE; + + if(conn->socks_proxy.host.rawalloc) { + if(!conn->http_proxy.host.rawalloc) { + /* once a socks proxy */ + if(!conn->socks_proxy.user) { + conn->socks_proxy.user = conn->http_proxy.user; + conn->http_proxy.user = NULL; + Curl_safefree(conn->socks_proxy.passwd); + conn->socks_proxy.passwd = conn->http_proxy.passwd; + conn->http_proxy.passwd = NULL; + } + } + conn->bits.socksproxy = TRUE; + } + else + conn->bits.socksproxy = FALSE; /* not a socks proxy */ } else { + conn->bits.socksproxy = FALSE; + conn->bits.httpproxy = FALSE; + } + conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy; + + if(!conn->bits.proxy) { /* we aren't using the proxy after all... */ conn->bits.proxy = FALSE; conn->bits.httpproxy = FALSE; + conn->bits.socksproxy = FALSE; conn->bits.proxy_user_passwd = FALSE; conn->bits.tunnel_proxy = FALSE; } @@ -6001,18 +6441,20 @@ static CURLcode create_conn(struct SessionHandle *data, /************************************************************* * IDN-fix the hostnames *************************************************************/ - fix_hostname(data, conn, &conn->host); + fix_hostname(conn, &conn->host); if(conn->bits.conn_to_host) - fix_hostname(data, conn, &conn->conn_to_host); - if(conn->proxy.name && *conn->proxy.name) - fix_hostname(data, conn, &conn->proxy); + fix_hostname(conn, &conn->conn_to_host); + if(conn->bits.httpproxy) + fix_hostname(conn, &conn->http_proxy.host); + if(conn->bits.socksproxy) + fix_hostname(conn, &conn->socks_proxy.host); /************************************************************* * Check whether the host and the "connect to host" are equal. - * Do this after the hostnames have been IDN-fixed . + * Do this after the hostnames have been IDN-fixed. *************************************************************/ if(conn->bits.conn_to_host && - Curl_raw_equal(conn->conn_to_host.name, conn->host.name)) { + strcasecompare(conn->conn_to_host.name, conn->host.name)) { conn->bits.conn_to_host = FALSE; } @@ -6093,22 +6535,54 @@ static CURLcode create_conn(struct SessionHandle *data, strings in the session handle strings array! Keep in mind that the pointers in the master copy are pointing to strings - that will be freed as part of the SessionHandle struct, but all cloned + that will be freed as part of the Curl_easy struct, but all cloned copies will be separately allocated. */ - data->set.ssl.CApath = data->set.str[STRING_SSL_CAPATH]; - data->set.ssl.CAfile = data->set.str[STRING_SSL_CAFILE]; - data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE]; - data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT]; - data->set.ssl.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; - data->set.ssl.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; - data->set.ssl.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST]; + data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_ORIG]; + data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY]; + data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_ORIG]; + data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY]; + data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE]; + data->set.proxy_ssl.primary.random_file = + data->set.str[STRING_SSL_RANDOM_FILE]; + data->set.ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; + data->set.proxy_ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET]; + data->set.ssl.primary.cipher_list = + data->set.str[STRING_SSL_CIPHER_LIST_ORIG]; + data->set.proxy_ssl.primary.cipher_list = + data->set.str[STRING_SSL_CIPHER_LIST_PROXY]; + + data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG]; + data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY]; + data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG]; + data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY]; + data->set.ssl.cert = data->set.str[STRING_CERT_ORIG]; + data->set.proxy_ssl.cert = data->set.str[STRING_CERT_PROXY]; + data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG]; + data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY]; + data->set.ssl.key = data->set.str[STRING_KEY_ORIG]; + data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY]; + data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE_ORIG]; + data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY]; + data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_ORIG]; + data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY]; + data->set.ssl.primary.clientcert = data->set.str[STRING_CERT_ORIG]; + data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY]; #ifdef USE_TLS_SRP - data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME]; - data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD]; + data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_ORIG]; + data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY]; + data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_ORIG]; + data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY]; #endif - if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config)) { + if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary, + &conn->ssl_config)) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + + if(!Curl_clone_primary_ssl_config(&data->set.proxy_ssl.primary, + &conn->proxy_ssl_config)) { result = CURLE_OUT_OF_MEMORY; goto out; } @@ -6165,7 +6639,9 @@ static CURLcode create_conn(struct SessionHandle *data, infof(data, "Re-using existing connection! (#%ld) with %s %s\n", conn->connection_id, conn->bits.proxy?"proxy":"host", - conn->proxy.name?conn->proxy.dispname:conn->host.dispname); + conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname : + conn->http_proxy.host.name ? conn->http_proxy.host.dispname : + conn->host.dispname); } else { /* We have decided that we want a new connection. However, we may not @@ -6296,6 +6772,7 @@ static CURLcode create_conn(struct SessionHandle *data, free(options); free(passwd); free(user); + free(socksproxy); free(proxy); return result; } @@ -6312,7 +6789,7 @@ CURLcode Curl_setup_conn(struct connectdata *conn, bool *protocol_done) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; Curl_pgrsTime(data, TIMER_NAMELOOKUP); @@ -6386,7 +6863,7 @@ CURLcode Curl_setup_conn(struct connectdata *conn, return result; } -CURLcode Curl_connect(struct SessionHandle *data, +CURLcode Curl_connect(struct Curl_easy *data, struct connectdata **in_connect, bool *asyncp, bool *protocol_done) @@ -6429,14 +6906,14 @@ CURLcode Curl_connect(struct SessionHandle *data, /* * Curl_init_do() inits the readwrite session. This is inited each time (in * the DO function before the protocol-specific DO functions are invoked) for - * a transfer, sometimes multiple times on the same SessionHandle. Make sure + * a transfer, sometimes multiple times on the same Curl_easy. Make sure * nothing in here depends on stuff that are setup dynamically for the * transfer. * * Allow this function to get called with 'conn' set to NULL. */ -CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn) +CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn) { struct SingleRequest *k = &data->req; diff --git a/contrib/curl/lib/url.h b/contrib/curl/lib/url.h index 2b25731e..f13c8e66 100644 --- a/contrib/curl/lib/url.h +++ b/contrib/curl/lib/url.h @@ -27,15 +27,15 @@ * Prototypes for library-wide functions provided by url.c */ -CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn); -CURLcode Curl_open(struct SessionHandle **curl); +CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn); +CURLcode Curl_open(struct Curl_easy **curl); CURLcode Curl_init_userdefined(struct UserDefined *set); -CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, +CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option, va_list arg); -CURLcode Curl_dupset(struct SessionHandle * dst, struct SessionHandle * src); -void Curl_freeset(struct SessionHandle * data); -CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */ -CURLcode Curl_connect(struct SessionHandle *, struct connectdata **, +CURLcode Curl_dupset(struct Curl_easy * dst, struct Curl_easy * src); +void Curl_freeset(struct Curl_easy * data); +CURLcode Curl_close(struct Curl_easy *data); /* opposite of curl_open() */ +CURLcode Curl_connect(struct Curl_easy *, struct connectdata **, bool *async, bool *protocol_connect); CURLcode Curl_disconnect(struct connectdata *, bool dead_connection); CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done); @@ -43,7 +43,7 @@ CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done); CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done); CURLcode Curl_setup_conn(struct connectdata *conn, bool *protocol_done); -void Curl_free_request_state(struct SessionHandle *data); +void Curl_free_request_state(struct Curl_easy *data); int Curl_protocol_getsock(struct connectdata *conn, curl_socket_t *socks, @@ -52,21 +52,23 @@ int Curl_doing_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks); -bool Curl_isPipeliningEnabled(const struct SessionHandle *handle); -CURLcode Curl_addHandleToPipeline(struct SessionHandle *handle, +bool Curl_isPipeliningEnabled(const struct Curl_easy *handle); +CURLcode Curl_addHandleToPipeline(struct Curl_easy *handle, struct curl_llist *pipeline); -int Curl_removeHandleFromPipeline(struct SessionHandle *handle, +int Curl_removeHandleFromPipeline(struct Curl_easy *handle, struct curl_llist *pipeline); struct connectdata * -Curl_oldest_idle_connection(struct SessionHandle *data); +Curl_oldest_idle_connection(struct Curl_easy *data); /* remove the specified connection from all (possible) pipelines and related queues */ -void Curl_getoff_all_pipelines(struct SessionHandle *data, +void Curl_getoff_all_pipelines(struct Curl_easy *data, struct connectdata *conn); -void Curl_close_connections(struct SessionHandle *data); +void Curl_close_connections(struct Curl_easy *data); #define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */ +#define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless + specified */ CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex); @@ -76,5 +78,16 @@ CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex); void Curl_verboseconnect(struct connectdata *conn); #endif +#define CONNECT_PROXY_SSL()\ + (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\ + !conn->bits.proxy_ssl_connected[sockindex]) + +#define CONNECT_FIRSTSOCKET_PROXY_SSL()\ + (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\ + !conn->bits.proxy_ssl_connected[FIRSTSOCKET]) + +#define CONNECT_SECONDARYSOCKET_PROXY_SSL()\ + (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\ + !conn->bits.proxy_ssl_connected[SECONDARYSOCKET]) #endif /* HEADER_CURL_URL_H */ diff --git a/contrib/curl/lib/urldata.h b/contrib/curl/lib/urldata.h index 25594d3b..7f87913a 100644 --- a/contrib/curl/lib/urldata.h +++ b/contrib/curl/lib/urldata.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -136,8 +136,10 @@ #undef realloc #endif /* USE_AXTLS */ -#ifdef USE_SCHANNEL +#if defined(USE_SCHANNEL) || defined(USE_WINDOWS_SSPI) #include "curl_sspi.h" +#endif +#ifdef USE_SCHANNEL #include #include #endif @@ -201,6 +203,9 @@ /* Download buffer size, keep it fairly big for speed reasons */ #undef BUFSIZE #define BUFSIZE CURL_MAX_WRITE_SIZE +#undef MAX_BUFSIZE +#define MAX_BUFSIZE CURL_MAX_READ_SIZE +#define CURL_BUFSIZE(x) ((x)?(x):(BUFSIZE)) /* Initial size of the buffer to store headers in, it'll be enlarged in case of need. */ @@ -208,14 +213,13 @@ #define CURLEASY_MAGIC_NUMBER 0xc0dedbadU #define GOOD_EASY_HANDLE(x) \ - ((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER)) + ((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER)) /* Some convenience macros to get the larger/smaller value out of two given. We prefix with CURL to prevent name collisions. */ #define CURLMAX(x,y) ((x)>(y)?(x):(y)) #define CURLMIN(x,y) ((x)<(y)?(x):(y)) - #ifdef HAVE_GSSAPI /* Types needed for krb5-ftp connections */ struct krb5buffer { @@ -242,7 +246,6 @@ struct curl_schannel_cred { CredHandle cred_handle; TimeStamp time_stamp; int refcount; - bool cached; }; struct curl_schannel_ctxt { @@ -312,12 +315,14 @@ struct ssl_connect_data { #elif defined(USE_NSS) PRFileDesc *handle; char *client_nickname; - struct SessionHandle *data; + struct Curl_easy *data; struct curl_llist *obj_list; PK11GenericObject *obj_clicert; #elif defined(USE_GSKIT) gsk_handle handle; int iocport; + int localfd; + int remotefd; #elif defined(USE_AXTLS) SSL_CTX* ssl_ctx; SSL* ssl; @@ -332,6 +337,7 @@ struct ssl_connect_data { CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ bool recv_sspi_close_notify; /* true if connection closed by close_notify */ bool recv_connection_closed; /* true if connection closed, regardless how */ + bool use_alpn; /* true if ALPN is used for this connection */ #elif defined(USE_DARWINSSL) SSLContextRef ssl_ctx; curl_socket_t ssl_sockfd; @@ -342,27 +348,38 @@ struct ssl_connect_data { #endif }; -struct ssl_config_data { +struct ssl_primary_config { long version; /* what version the client wants to use */ - long certverifyresult; /* result from the certificate verification */ - bool verifypeer; /* set TRUE if this is desired */ bool verifyhost; /* set TRUE if CN/SAN must match hostname */ bool verifystatus; /* set TRUE if certificate status must be checked */ char *CApath; /* certificate dir (doesn't work on windows) */ char *CAfile; /* certificate to verify peer against */ - const char *CRLfile; /* CRL to check certificate revocation */ - const char *issuercert;/* optional issuer certificate filename */ + char *clientcert; char *random_file; /* path to file containing "random" data */ char *egdsocket; /* path to file containing the EGD daemon socket */ char *cipher_list; /* list of ciphers to use */ - size_t max_ssl_sessions; /* SSL session id cache size */ +}; + +struct ssl_config_data { + struct ssl_primary_config primary; + bool enable_beast; /* especially allow this flaw for interoperability's + sake*/ + bool no_revoke; /* disable SSL certificate revocation checks */ + long certverifyresult; /* result from the certificate verification */ + char *CRLfile; /* CRL to check certificate revocation */ + char *issuercert;/* optional issuer certificate filename */ curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */ void *fsslctxp; /* parameter for call back */ - bool sessionid; /* cache session IDs or not */ bool certinfo; /* gather lots of certificate info */ bool falsestart; + char *cert; /* client certificate file name */ + char *cert_type; /* format for certificate (default: PEM)*/ + char *key; /* private key file name */ + char *key_type; /* format for private key (default: PEM) */ + char *key_passwd; /* plain text private key password */ + #ifdef USE_TLS_SRP char *username; /* TLS username (for, e.g., SRP) */ char *password; /* TLS password (for, e.g., SRP) */ @@ -370,16 +387,22 @@ struct ssl_config_data { #endif }; +struct ssl_general_config { + bool sessionid; /* cache session IDs or not */ + size_t max_ssl_sessions; /* SSL session id cache size */ +}; + /* information stored about one single SSL session */ struct curl_ssl_session { char *name; /* host name for which this ID was used */ char *conn_to_host; /* host name for the connection (may be NULL) */ + const char *scheme; /* protocol scheme used */ void *sessionid; /* as returned from the SSL layer */ size_t idsize; /* if known, otherwise 0 */ long age; /* just a number, the higher the more recent */ int remote_port; /* remote port */ int conn_to_port; /* remote port for the connection (may be -1) */ - struct ssl_config_data ssl_config; /* setup for this session */ + struct ssl_primary_config ssl_config; /* setup for this session */ }; /* Struct used for Digest challenge-response authentication */ @@ -387,6 +410,7 @@ struct digestdata { #if defined(USE_WINDOWS_SSPI) BYTE *input_token; size_t input_token_len; + CtxtHandle *http_context; #else char *nonce; char *cnonce; @@ -450,7 +474,7 @@ struct ntlmdata { #else unsigned int flags; unsigned char nonce[8]; - void* target_info; /* TargetInfo received in the ntlm type-2 message */ + void *target_info; /* TargetInfo received in the ntlm type-2 message */ unsigned int target_info_len; #endif }; @@ -496,6 +520,7 @@ struct ConnectBits { that overrides the port in the URL (remote port) */ bool proxy; /* if set, this transfer is done through a proxy - any type */ bool httpproxy; /* if set, this transfer is done through a http proxy */ + bool socksproxy; /* if set, this transfer is done through a socks proxy */ bool user_passwd; /* do we use user+password for this connection? */ bool proxy_user_passwd; /* user+password for the proxy? */ bool ipv6_ip; /* we communicate with a remote site specified with pure IPv6 @@ -530,6 +555,7 @@ struct ConnectBits { bool ftp_use_eprt; /* As set with CURLOPT_FTP_USE_EPRT, but if we find out EPRT doesn't work we disable it for the forthcoming requests */ + bool ftp_use_data_ssl; /* Enabled SSL for the data connection */ bool netrc; /* name+password provided by netrc */ bool userpwd_in_url; /* name+password found in url */ bool stream_was_rewound; /* Indicates that the stream was rewound after a @@ -546,6 +572,9 @@ struct ConnectBits { bool tcp_fastopen; /* use TCP Fast Open */ bool tls_enable_npn; /* TLS NPN extension? */ bool tls_enable_alpn; /* TLS ALPN extension? */ + bool proxy_ssl_connected[2]; /* TRUE when SSL initialization for HTTPS proxy + is complete */ + bool socksproxy_connecting; /* connecting through a socks proxy */ }; struct hostname { @@ -619,9 +648,9 @@ enum upgrade101 { }; /* - * Request specific data in the easy handle (SessionHandle). Previously, + * Request specific data in the easy handle (Curl_easy). Previously, * these members were on the connectdata struct but since a conn struct may - * now be shared between different SessionHandles, we store connection-specific + * now be shared between different Curl_easys, we store connection-specific * data here. This struct only keeps stuff that's interesting for *this* * request, as it will be cleared between multiple ones */ @@ -731,7 +760,7 @@ struct SingleRequest { */ struct Curl_handler { - const char * scheme; /* URL scheme name. */ + const char *scheme; /* URL scheme name. */ /* Complement to setup_connection_internals(). */ CURLcode (*setup_connection)(struct connectdata *); @@ -792,7 +821,7 @@ struct Curl_handler { /* If used, this function gets called from transfer.c:readwrite_data() to allow the protocol to do extra reads/writes */ - CURLcode (*readwrite)(struct SessionHandle *data, struct connectdata *conn, + CURLcode (*readwrite)(struct Curl_easy *data, struct connectdata *conn, ssize_t *nread, bool *readmore); long defport; /* Default port. */ @@ -818,6 +847,9 @@ struct Curl_handler { #define PROTOPT_CREDSPERREQUEST (1<<7) /* requires login credentials per request instead of per connection */ #define PROTOPT_ALPN_NPN (1<<8) /* set ALPN and/or NPN for this */ +#define PROTOPT_STREAM (1<<9) /* a protocol with individual logical streams */ +#define PROTOPT_URLOPTIONS (1<<10) /* allow options part in the userinfo field + of the URL */ /* return the count of bytes sent, or -1 on error */ typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */ @@ -847,15 +879,23 @@ struct postponed_data { }; #endif /* USE_RECV_BEFORE_SEND_WORKAROUND */ +struct proxy_info { + struct hostname host; + long port; + curl_proxytype proxytype; /* what kind of proxy that is in use */ + char *user; /* proxy user name string, allocated */ + char *passwd; /* proxy password string, allocated */ +}; + /* * The connectdata struct contains all fields and variables that should be * unique for an entire connection. */ struct connectdata { - /* 'data' is the CURRENT SessionHandle using this connection -- take great + /* 'data' is the CURRENT Curl_easy using this connection -- take great caution that this might very well vary between different times this connection is used! */ - struct SessionHandle *data; + struct Curl_easy *data; /* chunk is for HTTP chunked encoding, but is in the general connectdata struct only because we can do just about any protocol through a HTTP proxy @@ -896,14 +936,19 @@ struct connectdata { int socktype; /* SOCK_STREAM or SOCK_DGRAM */ struct hostname host; + char *secondaryhostname; /* secondary socket host name (ftp) */ struct hostname conn_to_host; /* the host to connect to. valid only if bits.conn_to_host is set */ - struct hostname proxy; + + struct proxy_info socks_proxy; + struct proxy_info http_proxy; long port; /* which port to use locally */ int remote_port; /* the remote port, not the proxy port! */ int conn_to_port; /* the remote port to connect to. valid only if bits.conn_to_port is set */ + unsigned short secondary_port; /* secondary socket remote port to connect to + (ftp) */ /* 'primary_ip' and 'primary_port' get filled with peer's numerical ip address and port number whenever an outgoing connection is @@ -928,10 +973,6 @@ struct connectdata { char *oauth_bearer; /* bearer token for OAuth 2.0, allocated */ - char *proxyuser; /* proxy user name string, allocated */ - char *proxypasswd; /* proxy password string, allocated */ - curl_proxytype proxytype; /* what kind of proxy that is in use */ - int httpversion; /* the HTTP version*10 reported by the server */ int rtspversion; /* the RTSP version*10 reported by the server */ @@ -949,7 +990,9 @@ struct connectdata { struct postponed_data postponed[2]; /* two buffers for two sockets */ #endif /* USE_RECV_BEFORE_SEND_WORKAROUND */ struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */ - struct ssl_config_data ssl_config; + struct ssl_connect_data proxy_ssl[2]; /* this is for proxy ssl-stuff */ + struct ssl_primary_config ssl_config; + struct ssl_primary_config proxy_ssl_config; bool tls_upgraded; struct ConnectBits bits; /* various state-flags for this connection */ @@ -960,13 +1003,13 @@ struct connectdata { struct timeval connecttime; /* The two fields below get set in Curl_connecthost */ int num_addr; /* number of addresses to try to connect to */ - long timeoutms_per_addr; /* how long time in milliseconds to spend on - trying to connect to each IP address */ + time_t timeoutms_per_addr; /* how long time in milliseconds to spend on + trying to connect to each IP address */ const struct Curl_handler *handler; /* Connection's protocol handler */ const struct Curl_handler *given; /* The protocol first given */ - long ip_version; /* copied from the SessionHandle at creation time */ + long ip_version; /* copied from the Curl_easy at creation time */ /**** curl_get() phase fields */ @@ -1018,7 +1061,7 @@ struct connectdata { send on this pipeline */ struct curl_llist *recv_pipe; /* List of handles waiting to read their responses on this pipeline */ - char* master_buffer; /* The master buffer allocated on-demand; + char *master_buffer; /* The master buffer allocated on-demand; used for pipelining. */ size_t read_pos; /* Current read position in the master buffer */ size_t buf_len; /* Length of the buffer?? */ @@ -1039,8 +1082,8 @@ struct connectdata { /* used for communication with Samba's winbind daemon helper ntlm_auth */ curl_socket_t ntlm_auth_hlpr_socket; pid_t ntlm_auth_hlpr_pid; - char* challenge_header; - char* response_header; + char *challenge_header; + char *response_header; #endif #endif @@ -1076,9 +1119,6 @@ struct connectdata { int socks5_gssapi_enctype; #endif - bool verifypeer; - bool verifyhost; - /* When this connection is created, store the conditions for the local end bind. This is stored before the actual bind and before any connection is made and will serve the purpose of being used for comparison reasons so @@ -1097,15 +1137,21 @@ struct connectdata { struct connectbundle *bundle; /* The bundle we are member of */ int negnpn; /* APLN or NPN TLS negotiated protocol, CURL_HTTP_VERSION* */ + +#ifdef USE_UNIX_SOCKETS + char *unix_domain_socket; + bool abstract_unix_socket; +#endif }; /* The end of connectdata. */ /* * Struct to keep statistical and informational data. + * All variables in this struct must be initialized/reset in Curl_initinfo(). */ struct PureInfo { - int httpcode; /* Recent HTTP, FTP, or RTSP response code */ + int httpcode; /* Recent HTTP, FTP, RTSP or SMTP response code */ int httpproxycode; /* response code from proxy when received separate */ int httpversion; /* the http version number X.Y = X*10+Y */ long filetime; /* If requested, this is might get set. Set to -1 if the time @@ -1136,6 +1182,9 @@ struct PureInfo { char conn_local_ip[MAX_IPADR_LEN]; long conn_local_port; + const char *conn_scheme; + unsigned int conn_protocol; + struct curl_certinfo certs; /* info about the certs, only populated in OpenSSL builds. Asked for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */ @@ -1143,8 +1192,8 @@ struct PureInfo { struct Progress { - long lastshow; /* time() of the last displayed progress meter or NULL to - force redraw at next call */ + time_t lastshow; /* time() of the last displayed progress meter or NULL to + force redraw at next call */ curl_off_t size_dl; /* total expected size */ curl_off_t size_ul; /* total expected size */ curl_off_t downloaded; /* transferred so far */ @@ -1172,6 +1221,14 @@ struct Progress { struct timeval t_startsingle; struct timeval t_startop; struct timeval t_acceptdata; + + /* upload speed limit */ + struct timeval ul_limit_start; + curl_off_t ul_limit_size; + /* download speed limit */ + struct timeval dl_limit_start; + curl_off_t dl_limit_size; + #define CURR_TIME (5+1) /* 6 entries for 5 seconds */ curl_off_t speeder[ CURR_TIME ]; @@ -1209,7 +1266,7 @@ typedef enum { /* * Values that are generated, temporary or calculated internally for a * "session handle" must be defined within the 'struct UrlState'. This struct - * will be used within the SessionHandle struct. When the 'SessionHandle' + * will be used within the Curl_easy struct. When the 'Curl_easy' * struct is cloned, this data MUST NOT be copied. * * Remember that any "state" information goes globally for the curl handle. @@ -1231,6 +1288,11 @@ struct auth { be RFC compliant */ }; +struct Curl_http2_dep { + struct Curl_http2_dep *next; + struct Curl_easy *data; +}; + struct UrlState { /* Points to the connection cache */ @@ -1249,7 +1311,7 @@ struct UrlState { char *headerbuff; /* allocated buffer to store headers in */ size_t headersize; /* size of the allocation */ - char buffer[BUFSIZE+1]; /* download buffer */ + char *buffer; /* download buffer */ char uploadbuffer[BUFSIZE+1]; /* upload buffer */ curl_off_t current_speed; /* the ProgressShow() funcion sets this, bytes / second */ @@ -1348,14 +1410,14 @@ struct UrlState { size_t drain; /* Increased when this stream has data to read, even if its socket is not necessarily is readable. Decreased when checked. */ - bool done; /* set to FALSE when Curl_do() is called and set to TRUE when - Curl_done() is called, to prevent Curl_done() to get invoked - twice when the multi interface is used. */ + bool done; /* set to FALSE when Curl_init_do() is called and set to TRUE + when multi_done() is called, to prevent multi_done() to get + invoked twice when the multi interface is used. */ curl_read_callback fread_func; /* read callback/function */ void *in; /* CURLOPT_READDATA */ - struct SessionHandle *stream_depends_on; + struct Curl_easy *stream_depends_on; bool stream_depends_e; /* set or don't set the Exclusive bit */ int stream_weight; }; @@ -1391,8 +1453,10 @@ struct DynamicStatic { struct Curl_multi; /* declared and used only in multi.c */ enum dupstring { - STRING_CERT, /* client certificate file name */ - STRING_CERT_TYPE, /* format for certificate (default: PEM)*/ + STRING_CERT_ORIG, /* client certificate file name */ + STRING_CERT_PROXY, /* client certificate file name */ + STRING_CERT_TYPE_ORIG, /* format for certificate (default: PEM)*/ + STRING_CERT_TYPE_PROXY, /* format for certificate (default: PEM)*/ STRING_COOKIE, /* HTTP cookie string to send */ STRING_COOKIEJAR, /* dump all cookies to this file */ STRING_CUSTOMREQUEST, /* HTTP/FTP/RTSP request/method to use */ @@ -1402,25 +1466,35 @@ enum dupstring { STRING_FTP_ACCOUNT, /* ftp account data */ STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */ STRING_FTPPORT, /* port to send with the FTP PORT command */ - STRING_KEY, /* private key file name */ - STRING_KEY_PASSWD, /* plain text private key password */ - STRING_KEY_TYPE, /* format for private key (default: PEM) */ + STRING_KEY_ORIG, /* private key file name */ + STRING_KEY_PROXY, /* private key file name */ + STRING_KEY_PASSWD_ORIG, /* plain text private key password */ + STRING_KEY_PASSWD_PROXY, /* plain text private key password */ + STRING_KEY_TYPE_ORIG, /* format for private key (default: PEM) */ + STRING_KEY_TYPE_PROXY, /* format for private key (default: PEM) */ STRING_KRB_LEVEL, /* krb security level */ STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find $HOME/.netrc */ STRING_PROXY, /* proxy to use */ + STRING_PRE_PROXY, /* pre socks proxy to use */ STRING_SET_RANGE, /* range, if used */ STRING_SET_REFERER, /* custom string for the HTTP referer field */ STRING_SET_URL, /* what original URL to work on */ - STRING_SSL_CAPATH, /* CA directory name (doesn't work on windows) */ - STRING_SSL_CAFILE, /* certificate file to verify peer against */ - STRING_SSL_PINNEDPUBLICKEY, /* public key file to verify peer against */ - STRING_SSL_CIPHER_LIST, /* list of ciphers to use */ + STRING_SSL_CAPATH_ORIG, /* CA directory name (doesn't work on windows) */ + STRING_SSL_CAPATH_PROXY, /* CA directory name (doesn't work on windows) */ + STRING_SSL_CAFILE_ORIG, /* certificate file to verify peer against */ + STRING_SSL_CAFILE_PROXY, /* certificate file to verify peer against */ + STRING_SSL_PINNEDPUBLICKEY_ORIG, /* public key file to verify peer against */ + STRING_SSL_PINNEDPUBLICKEY_PROXY, /* public key file to verify proxy */ + STRING_SSL_CIPHER_LIST_ORIG, /* list of ciphers to use */ + STRING_SSL_CIPHER_LIST_PROXY, /* list of ciphers to use */ STRING_SSL_EGDSOCKET, /* path to file containing the EGD daemon socket */ STRING_SSL_RANDOM_FILE, /* path to file containing "random" data */ STRING_USERAGENT, /* User-Agent string */ - STRING_SSL_CRLFILE, /* crl file to check certificate */ - STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */ + STRING_SSL_CRLFILE_ORIG, /* crl file to check certificate */ + STRING_SSL_CRLFILE_PROXY, /* crl file to check certificate */ + STRING_SSL_ISSUERCERT_ORIG, /* issuer cert file to check certificate */ + STRING_SSL_ISSUERCERT_PROXY, /* issuer cert file to check certificate */ STRING_USERNAME, /* , if used */ STRING_PASSWORD, /* , if used */ STRING_OPTIONS, /* , if used */ @@ -1448,8 +1522,10 @@ enum dupstring { STRING_MAIL_AUTH, #ifdef USE_TLS_SRP - STRING_TLSAUTH_USERNAME, /* TLS auth */ - STRING_TLSAUTH_PASSWORD, /* TLS auth */ + STRING_TLSAUTH_USERNAME_ORIG, /* TLS auth */ + STRING_TLSAUTH_USERNAME_PROXY, /* TLS auth */ + STRING_TLSAUTH_PASSWORD_ORIG, /* TLS auth */ + STRING_TLSAUTH_PASSWORD_PROXY, /* TLS auth */ #endif STRING_BEARER, /* , if used */ #ifdef USE_UNIX_SOCKETS @@ -1513,10 +1589,10 @@ struct UserDefined { curl_opensocket_callback fopensocket; /* function for checking/translating the address and opening the socket */ - void* opensocket_client; + void *opensocket_client; curl_closesocket_callback fclosesocket; /* function for closing the socket */ - void* closesocket_client; + void *closesocket_client; void *seek_client; /* pointer to pass to the seek callback */ /* the 3 curl_conv_callback functions below are used on non-ASCII hosts */ @@ -1567,6 +1643,8 @@ struct UserDefined { long httpversion; /* when non-zero, a specific HTTP version requested to be used in the library's request(s) */ struct ssl_config_data ssl; /* user defined SSL stuff */ + struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */ + struct ssl_general_config general_ssl; /* general user defined SSL stuff */ curl_proxytype proxytype; /* what kind of proxy that is in use */ long dns_cache_timeout; /* DNS cache timeout */ long buffer_size; /* size of receive buffer to use */ @@ -1601,6 +1679,7 @@ struct UserDefined { bool ftp_use_port; /* use the FTP PORT command */ bool hide_progress; /* don't use the progress meter */ bool http_fail_on_error; /* fail on HTTP error codes >= 400 */ + bool http_keep_sending_on_error; /* for HTTP status codes >= 300 */ bool http_follow_location; /* follow HTTP redirects */ bool http_transfer_encoding; /* request compressed HTTP transfer-encoding */ bool http_disable_hostname_check_before_authentication; @@ -1630,9 +1709,6 @@ struct UserDefined { bool ftp_skip_ip; /* skip the IP address the FTP server passes on to us */ bool connect_only; /* make connection, let application use the socket */ - bool ssl_enable_beast; /* especially allow this flaw for interoperability's - sake*/ - bool ssl_no_revoke; /* disable SSL certificate revocation checks */ long ssh_auth_types; /* allowed SSH auth types */ bool http_te_skip; /* pass the raw body data to the user, even when transfer-encoded (chunked, compressed) */ @@ -1680,9 +1756,13 @@ struct UserDefined { new connection */ long expect_100_timeout; /* in milliseconds */ - struct SessionHandle *stream_depends_on; + struct Curl_easy *stream_depends_on; bool stream_depends_e; /* set or don't set the Exclusive bit */ int stream_weight; + + struct Curl_http2_dep *stream_dependents; + + bool abstract_unix_socket; }; struct Names { @@ -1705,10 +1785,10 @@ struct Names { * 'struct UrlState' instead. */ -struct SessionHandle { +struct Curl_easy { /* first, two fields for the linked list of these */ - struct SessionHandle *next; - struct SessionHandle *prev; + struct Curl_easy *next; + struct Curl_easy *prev; struct connectdata *easy_conn; /* the "unit's" connection */ diff --git a/contrib/curl/lib/vauth/cleartext.c b/contrib/curl/lib/vauth/cleartext.c index a003f51d..a761ae78 100644 --- a/contrib/curl/lib/vauth/cleartext.c +++ b/contrib/curl/lib/vauth/cleartext.c @@ -33,8 +33,6 @@ #include "curl_md5.h" #include "warnless.h" #include "strtok.h" -#include "strequal.h" -#include "rawstr.h" #include "sendf.h" #include "curl_printf.h" @@ -59,7 +57,7 @@ * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_plain_message(struct SessionHandle *data, +CURLcode Curl_auth_create_plain_message(struct Curl_easy *data, const char *userp, const char *passwdp, char **outptr, size_t *outlen) @@ -68,16 +66,27 @@ CURLcode Curl_auth_create_plain_message(struct SessionHandle *data, char *plainauth; size_t ulen; size_t plen; + size_t plainlen; + *outlen = 0; + *outptr = NULL; ulen = strlen(userp); plen = strlen(passwdp); - plainauth = malloc(2 * ulen + plen + 2); - if(!plainauth) { - *outlen = 0; - *outptr = NULL; + /* Compute binary message length, checking for overflows. */ + plainlen = 2 * ulen; + if(plainlen < ulen) + return CURLE_OUT_OF_MEMORY; + plainlen += plen; + if(plainlen < plen) + return CURLE_OUT_OF_MEMORY; + plainlen += 2; + if(plainlen < 2) + return CURLE_OUT_OF_MEMORY; + + plainauth = malloc(plainlen); + if(!plainauth) return CURLE_OUT_OF_MEMORY; - } /* Calculate the reply */ memcpy(plainauth, userp, ulen); @@ -87,8 +96,7 @@ CURLcode Curl_auth_create_plain_message(struct SessionHandle *data, memcpy(plainauth + 2 * ulen + 2, passwdp, plen); /* Base64 encode the reply */ - result = Curl_base64_encode(data, plainauth, 2 * ulen + plen + 2, outptr, - outlen); + result = Curl_base64_encode(data, plainauth, plainlen, outptr, outlen); free(plainauth); return result; @@ -110,7 +118,7 @@ CURLcode Curl_auth_create_plain_message(struct SessionHandle *data, * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_login_message(struct SessionHandle *data, +CURLcode Curl_auth_create_login_message(struct Curl_easy *data, const char *valuep, char **outptr, size_t *outlen) { @@ -148,7 +156,7 @@ CURLcode Curl_auth_create_login_message(struct SessionHandle *data, * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_external_message(struct SessionHandle *data, +CURLcode Curl_auth_create_external_message(struct Curl_easy *data, const char *user, char **outptr, size_t *outlen) { diff --git a/contrib/curl/lib/vauth/cram.c b/contrib/curl/lib/vauth/cram.c index cd02e04b..3074a163 100644 --- a/contrib/curl/lib/vauth/cram.c +++ b/contrib/curl/lib/vauth/cram.c @@ -88,7 +88,7 @@ CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr, * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_cram_md5_message(struct SessionHandle *data, +CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data, const char *chlg, const char *userp, const char *passwdp, diff --git a/contrib/curl/lib/vauth/digest.c b/contrib/curl/lib/vauth/digest.c index 72cf0482..7d9200ad 100644 --- a/contrib/curl/lib/vauth/digest.c +++ b/contrib/curl/lib/vauth/digest.c @@ -37,9 +37,10 @@ #include "vtls/vtls.h" #include "warnless.h" #include "strtok.h" -#include "rawstr.h" +#include "strcase.h" #include "non-ascii.h" /* included for Curl_convert_... prototypes */ #include "curl_printf.h" +#include "rand.h" /* The last #include files should be: */ #include "curl_memory.h" @@ -59,7 +60,7 @@ what ultimately goes over the network. */ #define CURL_OUTPUT_DIGEST_CONV(a, b) \ - result = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \ + result = Curl_convert_to_network(a, (char *)b, strlen((const char *)b)); \ if(result) { \ free(b); \ return result; \ @@ -217,11 +218,11 @@ static CURLcode auth_digest_get_qop_values(const char *options, int *value) token = strtok_r(tmp, ",", &tok_buf); while(token != NULL) { - if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) + if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) *value |= DIGEST_QOP_VALUE_AUTH; - else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) + else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) *value |= DIGEST_QOP_VALUE_AUTH_INT; - else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF)) + else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF)) *value |= DIGEST_QOP_VALUE_AUTH_CONF; token = strtok_r(NULL, ",", &tok_buf); @@ -305,6 +306,20 @@ static CURLcode auth_decode_digest_md5_message(const char *chlg64, return CURLE_OK; } +/* + * Curl_auth_is_digest_supported() + * + * This is used to evaluate if DIGEST is supported. + * + * Parameters: None + * + * Returns TRUE as DIGEST as handled by libcurl. + */ +bool Curl_auth_is_digest_supported(void) +{ + return TRUE; +} + /* * Curl_auth_create_digest_md5_message() * @@ -324,7 +339,7 @@ static CURLcode auth_decode_digest_md5_message(const char *chlg64, * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_digest_md5_message(struct SessionHandle *data, +CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, const char *chlg64, const char *userp, const char *passwdp, @@ -373,10 +388,9 @@ CURLcode Curl_auth_create_digest_md5_message(struct SessionHandle *data, return CURLE_BAD_CONTENT_ENCODING; /* Generate 16 bytes of random data */ - entropy[0] = Curl_rand(data); - entropy[1] = Curl_rand(data); - entropy[2] = Curl_rand(data); - entropy[3] = Curl_rand(data); + result = Curl_rand(data, &entropy[0], 4); + if(result) + return result; /* Convert the random data into a 32 byte hex string */ snprintf(cnonce, sizeof(cnonce), "%08x%08x%08x%08x", @@ -524,31 +538,31 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, /* Extract a value=content pair */ if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { - if(Curl_raw_equal(value, "nonce")) { + if(strcasecompare(value, "nonce")) { free(digest->nonce); digest->nonce = strdup(content); if(!digest->nonce) return CURLE_OUT_OF_MEMORY; } - else if(Curl_raw_equal(value, "stale")) { - if(Curl_raw_equal(content, "true")) { + else if(strcasecompare(value, "stale")) { + if(strcasecompare(content, "true")) { digest->stale = TRUE; digest->nc = 1; /* we make a new nonce now */ } } - else if(Curl_raw_equal(value, "realm")) { + else if(strcasecompare(value, "realm")) { free(digest->realm); digest->realm = strdup(content); if(!digest->realm) return CURLE_OUT_OF_MEMORY; } - else if(Curl_raw_equal(value, "opaque")) { + else if(strcasecompare(value, "opaque")) { free(digest->opaque); digest->opaque = strdup(content); if(!digest->opaque) return CURLE_OUT_OF_MEMORY; } - else if(Curl_raw_equal(value, "qop")) { + else if(strcasecompare(value, "qop")) { char *tok_buf; /* Tokenize the list and choose auth if possible, use a temporary clone of the buffer since strtok_r() ruins it */ @@ -558,10 +572,10 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, token = strtok_r(tmp, ",", &tok_buf); while(token != NULL) { - if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH)) { + if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) { foundAuth = TRUE; } - else if(Curl_raw_equal(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) { + else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) { foundAuthInt = TRUE; } token = strtok_r(NULL, ",", &tok_buf); @@ -583,15 +597,15 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, return CURLE_OUT_OF_MEMORY; } } - else if(Curl_raw_equal(value, "algorithm")) { + else if(strcasecompare(value, "algorithm")) { free(digest->algorithm); digest->algorithm = strdup(content); if(!digest->algorithm) return CURLE_OUT_OF_MEMORY; - if(Curl_raw_equal(content, "MD5-sess")) + if(strcasecompare(content, "MD5-sess")) digest->algo = CURLDIGESTALGO_MD5SESS; - else if(Curl_raw_equal(content, "MD5")) + else if(strcasecompare(content, "MD5")) digest->algo = CURLDIGESTALGO_MD5; else return CURLE_BAD_CONTENT_ENCODING; @@ -645,7 +659,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_digest_http_message(struct SessionHandle *data, +CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, const char *userp, const char *passwdp, const unsigned char *request, @@ -670,9 +684,12 @@ CURLcode Curl_auth_create_digest_http_message(struct SessionHandle *data, digest->nc = 1; if(!digest->cnonce) { + unsigned int rnd[4]; + result = Curl_rand(data, &rnd[0], 4); + if(result) + return result; snprintf(cnoncebuf, sizeof(cnoncebuf), "%08x%08x%08x%08x", - Curl_rand(data), Curl_rand(data), - Curl_rand(data), Curl_rand(data)); + rnd[0], rnd[1], rnd[2], rnd[3]); result = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), &cnonce, &cnonce_sz); @@ -730,7 +747,7 @@ CURLcode Curl_auth_create_digest_http_message(struct SessionHandle *data, md5this = (unsigned char *) aprintf("%s:%s", request, uripath); - if(digest->qop && Curl_raw_equal(digest->qop, "auth-int")) { + if(digest->qop && strcasecompare(digest->qop, "auth-int")) { /* We don't support auth-int for PUT or POST at the moment. TODO: replace md5 of empty string with entity-body for PUT/POST */ unsigned char *md5this2 = (unsigned char *) @@ -806,7 +823,7 @@ CURLcode Curl_auth_create_digest_http_message(struct SessionHandle *data, digest->qop, request_digest); - if(Curl_raw_equal(digest->qop, "auth")) + if(strcasecompare(digest->qop, "auth")) digest->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 padded which tells to the server how many times you are using the same nonce in the qop=auth mode */ diff --git a/contrib/curl/lib/vauth/digest_sspi.c b/contrib/curl/lib/vauth/digest_sspi.c index d13d08e5..15f3d8c1 100644 --- a/contrib/curl/lib/vauth/digest_sspi.c +++ b/contrib/curl/lib/vauth/digest_sspi.c @@ -37,12 +37,33 @@ #include "curl_multibyte.h" #include "sendf.h" #include "strdup.h" -#include "rawstr.h" +#include "strcase.h" /* The last #include files should be: */ #include "curl_memory.h" #include "memdebug.h" +/* +* Curl_auth_is_digest_supported() +* +* This is used to evaluate if DIGEST is supported. +* +* Parameters: None +* +* Returns TRUE if DIGEST is supported by Windows SSPI. +*/ +bool Curl_auth_is_digest_supported(void) +{ + PSecPkgInfo SecurityPackage; + SECURITY_STATUS status; + + /* Query the security package for Digest */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST), + &SecurityPackage); + + return (status == SEC_E_OK ? TRUE : FALSE); +} + /* * Curl_auth_create_digest_md5_message() * @@ -62,7 +83,7 @@ * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_digest_md5_message(struct SessionHandle *data, +CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, const char *chlg64, const char *userp, const char *passwdp, @@ -256,7 +277,7 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg, /* Extract a value=content pair */ if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) { - if(Curl_raw_equal(value, "realm")) { + if(strcasecompare(value, "realm")) { /* Setup identity's domain and length */ domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *) content); @@ -314,13 +335,44 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, { size_t chlglen = strlen(chlg); - /* We had an input token before and we got another one now. This means we - provided bad credentials in the previous request. */ - if(digest->input_token) - return CURLE_BAD_CONTENT_ENCODING; + /* We had an input token before so if there's another one now that means we + provided bad credentials in the previous request or it's stale. */ + if(digest->input_token) { + bool stale = false; + const char *p = chlg; - /* Simply store the challenge for use later */ - digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen); + /* Check for the 'stale' directive */ + for(;;) { + char value[DIGEST_MAX_VALUE_LENGTH]; + char content[DIGEST_MAX_CONTENT_LENGTH]; + + while(*p && ISSPACE(*p)) + p++; + + if(!Curl_auth_digest_get_pair(p, value, content, &p)) + break; + + if(Curl_strcasecompare(value, "stale") + && Curl_strcasecompare(content, "true")) { + stale = true; + break; + } + + while(*p && ISSPACE(*p)) + p++; + + if(',' == *p) + p++; + } + + if(stale) + Curl_auth_digest_cleanup(digest); + else + return CURLE_LOGIN_DENIED; + } + + /* Store the challenge for use later */ + digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen + 1); if(!digest->input_token) return CURLE_OUT_OF_MEMORY; @@ -349,7 +401,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_digest_http_message(struct SessionHandle *data, +CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, const char *userp, const char *passwdp, const unsigned char *request, @@ -358,21 +410,13 @@ CURLcode Curl_auth_create_digest_http_message(struct SessionHandle *data, char **outptr, size_t *outlen) { size_t token_max; - CredHandle credentials; - CtxtHandle context; char *resp; BYTE *output_token; + size_t output_token_len; PSecPkgInfo SecurityPackage; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; - SecBuffer chlg_buf[3]; - SecBuffer resp_buf; + SecBuffer chlg_buf[5]; SecBufferDesc chlg_desc; - SecBufferDesc resp_desc; SECURITY_STATUS status; - unsigned long attrs; - TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ - TCHAR *spn; (void) data; @@ -390,114 +434,165 @@ CURLcode Curl_auth_create_digest_http_message(struct SessionHandle *data, /* Allocate the output buffer according to the max token size as indicated by the security package */ output_token = malloc(token_max); - if(!output_token) - return CURLE_OUT_OF_MEMORY; - - if(userp && *userp) { - /* Populate our identity structure */ - if(Curl_create_sspi_identity(userp, passwdp, &identity)) - return CURLE_OUT_OF_MEMORY; - - /* Populate our identity domain */ - if(Curl_override_sspi_http_realm((const char*) digest->input_token, - &identity)) - return CURLE_OUT_OF_MEMORY; - - /* Allow proper cleanup of the identity structure */ - p_identity = &identity; - } - else - /* Use the current Windows user */ - p_identity = NULL; - - /* Acquire our credentials handle */ - status = s_pSecFn->AcquireCredentialsHandle(NULL, - (TCHAR *) TEXT(SP_NAME_DIGEST), - SECPKG_CRED_OUTBOUND, NULL, - p_identity, NULL, NULL, - &credentials, &expiry); - if(status != SEC_E_OK) { - Curl_sspi_free_identity(p_identity); - free(output_token); - - return CURLE_LOGIN_DENIED; - } - - /* Setup the challenge "input" security buffer if present */ - chlg_desc.ulVersion = SECBUFFER_VERSION; - chlg_desc.cBuffers = 3; - chlg_desc.pBuffers = chlg_buf; - chlg_buf[0].BufferType = SECBUFFER_TOKEN; - chlg_buf[0].pvBuffer = digest->input_token; - chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len); - chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; - chlg_buf[1].pvBuffer = (void *) request; - chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); - chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; - chlg_buf[2].pvBuffer = NULL; - chlg_buf[2].cbBuffer = 0; - - /* Setup the response "output" security buffer */ - resp_desc.ulVersion = SECBUFFER_VERSION; - resp_desc.cBuffers = 1; - resp_desc.pBuffers = &resp_buf; - resp_buf.BufferType = SECBUFFER_TOKEN; - resp_buf.pvBuffer = output_token; - resp_buf.cbBuffer = curlx_uztoul(token_max); - - spn = Curl_convert_UTF8_to_tchar((char *) uripath); - if(!spn) { - Curl_sspi_free_identity(p_identity); - free(output_token); - + if(!output_token) { return CURLE_OUT_OF_MEMORY; } - /* Generate our reponse message */ - status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, - spn, - ISC_REQ_USE_HTTP_STYLE, 0, 0, - &chlg_desc, 0, &context, - &resp_desc, &attrs, &expiry); - Curl_unicodefree(spn); + if(digest->http_context) { + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 5; + chlg_desc.pBuffers = chlg_buf; + chlg_buf[0].BufferType = SECBUFFER_TOKEN; + chlg_buf[0].pvBuffer = NULL; + chlg_buf[0].cbBuffer = 0; + chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[1].pvBuffer = (void *) request; + chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); + chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[2].pvBuffer = (void *) uripath; + chlg_buf[2].cbBuffer = curlx_uztoul(strlen((const char *) uripath)); + chlg_buf[3].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[3].pvBuffer = NULL; + chlg_buf[3].cbBuffer = 0; + chlg_buf[4].BufferType = SECBUFFER_PADDING; + chlg_buf[4].pvBuffer = output_token; + chlg_buf[4].cbBuffer = curlx_uztoul(token_max); + + status = s_pSecFn->MakeSignature(digest->http_context, 0, &chlg_desc, 0); + if(status == SEC_E_OK) + output_token_len = chlg_buf[4].cbBuffer; + else { /* delete the context so a new one can be made */ + infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx\n", + (long)status); + s_pSecFn->DeleteSecurityContext(digest->http_context); + Curl_safefree(digest->http_context); + } + } + + if(!digest->http_context) { + CredHandle credentials; + SEC_WINNT_AUTH_IDENTITY identity; + SEC_WINNT_AUTH_IDENTITY *p_identity; + SecBuffer resp_buf; + SecBufferDesc resp_desc; + unsigned long attrs; + TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ + TCHAR *spn; + + if(userp && *userp) { + /* Populate our identity structure */ + if(Curl_create_sspi_identity(userp, passwdp, &identity)) { + free(output_token); + return CURLE_OUT_OF_MEMORY; + } + + /* Populate our identity domain */ + if(Curl_override_sspi_http_realm((const char *) digest->input_token, + &identity)) { + free(output_token); + return CURLE_OUT_OF_MEMORY; + } + + /* Allow proper cleanup of the identity structure */ + p_identity = &identity; + } + else + /* Use the current Windows user */ + p_identity = NULL; + + /* Acquire our credentials handle */ + status = s_pSecFn->AcquireCredentialsHandle(NULL, + (TCHAR *) TEXT(SP_NAME_DIGEST), + SECPKG_CRED_OUTBOUND, NULL, + p_identity, NULL, NULL, + &credentials, &expiry); + if(status != SEC_E_OK) { + Curl_sspi_free_identity(p_identity); + free(output_token); + + return CURLE_LOGIN_DENIED; + } + + /* Setup the challenge "input" security buffer if present */ + chlg_desc.ulVersion = SECBUFFER_VERSION; + chlg_desc.cBuffers = 3; + chlg_desc.pBuffers = chlg_buf; + chlg_buf[0].BufferType = SECBUFFER_TOKEN; + chlg_buf[0].pvBuffer = digest->input_token; + chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len); + chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[1].pvBuffer = (void *) request; + chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request)); + chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS; + chlg_buf[2].pvBuffer = NULL; + chlg_buf[2].cbBuffer = 0; + + /* Setup the response "output" security buffer */ + resp_desc.ulVersion = SECBUFFER_VERSION; + resp_desc.cBuffers = 1; + resp_desc.pBuffers = &resp_buf; + resp_buf.BufferType = SECBUFFER_TOKEN; + resp_buf.pvBuffer = output_token; + resp_buf.cbBuffer = curlx_uztoul(token_max); + + spn = Curl_convert_UTF8_to_tchar((char *) uripath); + if(!spn) { + s_pSecFn->FreeCredentialsHandle(&credentials); + + Curl_sspi_free_identity(p_identity); + free(output_token); + + return CURLE_OUT_OF_MEMORY; + } + + /* Allocate our new context handle */ + digest->http_context = calloc(1, sizeof(CtxtHandle)); + if(!digest->http_context) + return CURLE_OUT_OF_MEMORY; + + /* Generate our reponse message */ + status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, + spn, + ISC_REQ_USE_HTTP_STYLE, 0, 0, + &chlg_desc, 0, + digest->http_context, + &resp_desc, &attrs, &expiry); + Curl_unicodefree(spn); + + if(status == SEC_I_COMPLETE_NEEDED || + status == SEC_I_COMPLETE_AND_CONTINUE) + s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); + else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { + s_pSecFn->FreeCredentialsHandle(&credentials); + + Curl_sspi_free_identity(p_identity); + free(output_token); + + Curl_safefree(digest->http_context); + + return CURLE_OUT_OF_MEMORY; + } + + output_token_len = resp_buf.cbBuffer; - if(status == SEC_I_COMPLETE_NEEDED || - status == SEC_I_COMPLETE_AND_CONTINUE) - s_pSecFn->CompleteAuthToken(&credentials, &resp_desc); - else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { s_pSecFn->FreeCredentialsHandle(&credentials); - Curl_sspi_free_identity(p_identity); - free(output_token); - - return CURLE_OUT_OF_MEMORY; } - resp = malloc(resp_buf.cbBuffer + 1); + resp = malloc(output_token_len + 1); if(!resp) { - s_pSecFn->DeleteSecurityContext(&context); - s_pSecFn->FreeCredentialsHandle(&credentials); - - Curl_sspi_free_identity(p_identity); free(output_token); return CURLE_OUT_OF_MEMORY; } /* Copy the generated reponse */ - memcpy(resp, resp_buf.pvBuffer, resp_buf.cbBuffer); - resp[resp_buf.cbBuffer] = 0x00; + memcpy(resp, output_token, output_token_len); + resp[output_token_len] = 0; /* Return the response */ *outptr = resp; - *outlen = resp_buf.cbBuffer; - - /* Free our handles */ - s_pSecFn->DeleteSecurityContext(&context); - s_pSecFn->FreeCredentialsHandle(&credentials); - - /* Free the identity structure */ - Curl_sspi_free_identity(p_identity); + *outlen = output_token_len; /* Free the response buffer */ free(output_token); @@ -522,6 +617,12 @@ void Curl_auth_digest_cleanup(struct digestdata *digest) /* Reset any variables */ digest->input_token_len = 0; + + /* Delete security context */ + if(digest->http_context) { + s_pSecFn->DeleteSecurityContext(digest->http_context); + Curl_safefree(digest->http_context); + } } #endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_CRYPTO_AUTH */ diff --git a/contrib/curl/lib/vauth/krb5_gssapi.c b/contrib/curl/lib/vauth/krb5_gssapi.c index 975675b5..c754fae4 100644 --- a/contrib/curl/lib/vauth/krb5_gssapi.c +++ b/contrib/curl/lib/vauth/krb5_gssapi.c @@ -41,6 +41,20 @@ #include "curl_memory.h" #include "memdebug.h" +/* + * Curl_auth_is_gssapi_supported() + * + * This is used to evaluate if GSSAPI (Kerberos V5) is supported. + * + * Parameters: None + * + * Returns TRUE if Kerberos V5 is supported by the GSS-API library. + */ +bool Curl_auth_is_gssapi_supported(void) +{ + return TRUE; +} + /* * Curl_auth_create_gssapi_user_message() * @@ -65,7 +79,7 @@ * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_gssapi_user_message(struct SessionHandle *data, +CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, const char *userp, const char *passwdp, const char *service, @@ -190,7 +204,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct SessionHandle *data, * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_gssapi_security_message(struct SessionHandle *data, +CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, const char *chlg64, struct kerberos5data *krb5, char **outptr, diff --git a/contrib/curl/lib/vauth/krb5_sspi.c b/contrib/curl/lib/vauth/krb5_sspi.c index bf56a64e..151794e6 100644 --- a/contrib/curl/lib/vauth/krb5_sspi.c +++ b/contrib/curl/lib/vauth/krb5_sspi.c @@ -39,6 +39,28 @@ #include "curl_memory.h" #include "memdebug.h" +/* + * Curl_auth_is_gssapi_supported() + * + * This is used to evaluate if GSSAPI (Kerberos V5) is supported. + * + * Parameters: None + * + * Returns TRUE if Kerberos V5 is supported by Windows SSPI. + */ +bool Curl_auth_is_gssapi_supported(void) +{ + PSecPkgInfo SecurityPackage; + SECURITY_STATUS status; + + /* Query the security package for Kerberos */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_KERBEROS), + &SecurityPackage); + + return (status == SEC_E_OK ? TRUE : FALSE); +} + /* * Curl_auth_create_gssapi_user_message() * @@ -62,7 +84,7 @@ * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_gssapi_user_message(struct SessionHandle *data, +CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, const char *userp, const char *passwdp, const char *service, @@ -240,7 +262,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct SessionHandle *data, * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_gssapi_security_message(struct SessionHandle *data, +CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, const char *chlg64, struct kerberos5data *krb5, char **outptr, diff --git a/contrib/curl/lib/vauth/ntlm.c b/contrib/curl/lib/vauth/ntlm.c index e27f4237..96861c93 100644 --- a/contrib/curl/lib/vauth/ntlm.c +++ b/contrib/curl/lib/vauth/ntlm.c @@ -27,7 +27,7 @@ /* * NTLM details: * - * http://davenport.sourceforge.net/ntlm.html + * https://davenport.sourceforge.io/ntlm.html * https://www.innovation.ch/java/ntlm.html */ @@ -41,7 +41,7 @@ #include "curl_gethostname.h" #include "curl_multibyte.h" #include "warnless.h" - +#include "rand.h" #include "vtls/vtls.h" #ifdef USE_NSS @@ -164,7 +164,7 @@ static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) * * Returns CURLE_OK on success. */ -static CURLcode ntlm_decode_type2_target(struct SessionHandle *data, +static CURLcode ntlm_decode_type2_target(struct Curl_easy *data, unsigned char *buffer, size_t size, struct ntlmdata *ntlm) @@ -216,6 +216,20 @@ static CURLcode ntlm_decode_type2_target(struct SessionHandle *data, from the beginning of the NTLM message. */ +/* + * Curl_auth_is_ntlm_supported() + * + * This is used to evaluate if NTLM is supported. + * + * Parameters: None + * + * Returns TRUE as NTLM as handled by libcurl. + */ +bool Curl_auth_is_ntlm_supported(void) +{ + return TRUE; +} + /* * Curl_auth_decode_ntlm_type2_message() * @@ -232,7 +246,7 @@ static CURLcode ntlm_decode_type2_target(struct SessionHandle *data, * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_decode_ntlm_type2_message(struct SessionHandle *data, +CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, const char *type2msg, struct ntlmdata *ntlm) { @@ -465,7 +479,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_ntlm_type3_message(struct SessionHandle *data, +CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, const char *userp, const char *passwdp, struct ntlmdata *ntlm, @@ -544,8 +558,9 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct SessionHandle *data, unsigned int entropy[2]; unsigned char ntlmv2hash[0x18]; - entropy[0] = Curl_rand(data); - entropy[1] = Curl_rand(data); + result = Curl_rand(data, &entropy[0], 2); + if(result) + return result; result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer); if(result) @@ -584,8 +599,9 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct SessionHandle *data, unsigned int entropy[2]; /* Need to create 8 bytes random data */ - entropy[0] = Curl_rand(data); - entropy[1] = Curl_rand(data); + result = Curl_rand(data, &entropy[0], 2); + if(result) + return result; /* 8 bytes random data as challenge in lmresp */ memcpy(lmresp, entropy, 8); @@ -635,7 +651,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct SessionHandle *data, /* A safer but less compatible alternative is: * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); - * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ + * See https://davenport.sourceforge.io/ntlm.html#ntlmVersion2 */ } if(unicode) { diff --git a/contrib/curl/lib/vauth/ntlm.h b/contrib/curl/lib/vauth/ntlm.h index b14e7a56..f906a3c7 100644 --- a/contrib/curl/lib/vauth/ntlm.h +++ b/contrib/curl/lib/vauth/ntlm.h @@ -32,7 +32,7 @@ /* Stuff only required for curl_ntlm_msgs.c */ #ifdef BUILDING_CURL_NTLM_MSGS_C -/* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */ +/* Flag bits definitions based on https://davenport.sourceforge.io/ntlm.html */ #define NTLMFLAG_NEGOTIATE_UNICODE (1<<0) /* Indicates that Unicode strings are supported for use in security buffer diff --git a/contrib/curl/lib/vauth/ntlm_sspi.c b/contrib/curl/lib/vauth/ntlm_sspi.c index 532e270f..c3305176 100644 --- a/contrib/curl/lib/vauth/ntlm_sspi.c +++ b/contrib/curl/lib/vauth/ntlm_sspi.c @@ -37,6 +37,27 @@ #include "curl_memory.h" #include "memdebug.h" +/* + * Curl_auth_is_ntlm_supported() + * + * This is used to evaluate if NTLM is supported. + * + * Parameters: None + * + * Returns TRUE if NTLM is supported by Windows SSPI. + */ +bool Curl_auth_is_ntlm_supported(void) +{ + PSecPkgInfo SecurityPackage; + SECURITY_STATUS status; + + /* Query the security package for NTLM */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM), + &SecurityPackage); + + return (status == SEC_E_OK ? TRUE : FALSE); +} + /* * Curl_auth_create_ntlm_type1_message() * @@ -162,7 +183,7 @@ CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_decode_ntlm_type2_message(struct SessionHandle *data, +CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, const char *type2msg, struct ntlmdata *ntlm) { @@ -214,7 +235,7 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct SessionHandle *data, * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_ntlm_type3_message(struct SessionHandle *data, +CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, const char *userp, const char *passwdp, struct ntlmdata *ntlm, diff --git a/contrib/curl/lib/vauth/oauth2.c b/contrib/curl/lib/vauth/oauth2.c index fccdfb86..6288f89a 100644 --- a/contrib/curl/lib/vauth/oauth2.c +++ b/contrib/curl/lib/vauth/oauth2.c @@ -55,7 +55,7 @@ * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_oauth_bearer_message(struct SessionHandle *data, +CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data, const char *user, const char *host, const long port, diff --git a/contrib/curl/lib/vauth/spnego_gssapi.c b/contrib/curl/lib/vauth/spnego_gssapi.c index 739e35b6..8840db8f 100644 --- a/contrib/curl/lib/vauth/spnego_gssapi.c +++ b/contrib/curl/lib/vauth/spnego_gssapi.c @@ -40,6 +40,20 @@ #include "curl_memory.h" #include "memdebug.h" +/* + * Curl_auth_is_spnego_supported() + * + * This is used to evaluate if SPNEGO (Negotiate) is supported. + * + * Parameters: None + * + * Returns TRUE if Negotiate supported by the GSS-API library. + */ +bool Curl_auth_is_spnego_supported(void) +{ + return TRUE; +} + /* * Curl_auth_decode_spnego_message() * @@ -58,7 +72,7 @@ * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_decode_spnego_message(struct SessionHandle *data, +CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, const char *user, const char *password, const char *service, @@ -187,7 +201,7 @@ CURLcode Curl_auth_decode_spnego_message(struct SessionHandle *data, * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_spnego_message(struct SessionHandle *data, +CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data, struct negotiatedata *nego, char **outptr, size_t *outlen) { @@ -229,7 +243,7 @@ CURLcode Curl_auth_create_spnego_message(struct SessionHandle *data, * nego [in/out] - The Negotiate data struct being cleaned up. * */ -void Curl_auth_spnego_cleanup(struct negotiatedata* nego) +void Curl_auth_spnego_cleanup(struct negotiatedata *nego) { OM_uint32 minor_status; diff --git a/contrib/curl/lib/vauth/spnego_sspi.c b/contrib/curl/lib/vauth/spnego_sspi.c index 79746647..5fa95e2e 100644 --- a/contrib/curl/lib/vauth/spnego_sspi.c +++ b/contrib/curl/lib/vauth/spnego_sspi.c @@ -39,6 +39,28 @@ #include "curl_memory.h" #include "memdebug.h" +/* + * Curl_auth_is_spnego_supported() + * + * This is used to evaluate if SPNEGO (Negotiate) is supported. + * + * Parameters: None + * + * Returns TRUE if Negotiate is supported by Windows SSPI. + */ +bool Curl_auth_is_spnego_supported(void) +{ + PSecPkgInfo SecurityPackage; + SECURITY_STATUS status; + + /* Query the security package for Negotiate */ + status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) + TEXT(SP_NAME_NEGOTIATE), + &SecurityPackage); + + return (status == SEC_E_OK ? TRUE : FALSE); +} + /* * Curl_auth_decode_spnego_message() * @@ -57,7 +79,7 @@ * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_decode_spnego_message(struct SessionHandle *data, +CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, const char *user, const char *password, const char *service, @@ -234,7 +256,7 @@ CURLcode Curl_auth_decode_spnego_message(struct SessionHandle *data, * * Returns CURLE_OK on success. */ -CURLcode Curl_auth_create_spnego_message(struct SessionHandle *data, +CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data, struct negotiatedata *nego, char **outptr, size_t *outlen) { @@ -242,15 +264,17 @@ CURLcode Curl_auth_create_spnego_message(struct SessionHandle *data, /* Base64 encode the already generated response */ result = Curl_base64_encode(data, - (const char*) nego->output_token, + (const char *) nego->output_token, nego->output_token_length, outptr, outlen); if(result) return result; - if(!*outptr || !*outlen) + if(!*outptr || !*outlen) { + free(*outptr); return CURLE_REMOTE_ACCESS_DENIED; + } return CURLE_OK; } @@ -265,7 +289,7 @@ CURLcode Curl_auth_create_spnego_message(struct SessionHandle *data, * nego [in/out] - The Negotiate data struct being cleaned up. * */ -void Curl_auth_spnego_cleanup(struct negotiatedata* nego) +void Curl_auth_spnego_cleanup(struct negotiatedata *nego) { /* Free our security context */ if(nego->context) { diff --git a/contrib/curl/lib/vauth/vauth.c b/contrib/curl/lib/vauth/vauth.c index 702e2d4b..b995f34e 100644 --- a/contrib/curl/lib/vauth/vauth.c +++ b/contrib/curl/lib/vauth/vauth.c @@ -104,3 +104,44 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host, } #endif /* USE_WINDOWS_SSPI */ +/* +* Curl_auth_user_contains_domain() +* +* This is used to test if the specified user contains a Windows domain name as +* follows: +* +* User\Domain (Down-level Logon Name) +* User/Domain (curl Down-level format - for compatibility with existing code) +* User@Domain (User Principal Name) +* +* Note: The user name may be empty when using a GSS-API library or Windows SSPI +* as the user and domain are either obtained from the credientals cache when +* using GSS-API or via the currently logged in user's credientals when using +* Windows SSPI. +* +* Parameters: +* +* user [in] - The user name. +* +* Returns TRUE on success; otherwise FALSE. +*/ +bool Curl_auth_user_contains_domain(const char *user) +{ + bool valid = FALSE; + + if(user && *user) { + /* Check we have a domain name or UPN present */ + char *p = strpbrk(user, "\\/@"); + + valid = (p != NULL && p > user && p < user + strlen(user) - 1 ? TRUE : + FALSE); + } +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + else + /* User and domain are obtained from the GSS-API credientials cache or the + currently logged in user from Windows */ + valid = TRUE; +#endif + + return valid; +} diff --git a/contrib/curl/lib/vauth/vauth.h b/contrib/curl/lib/vauth/vauth.h index 2c5131c7..9d61228c 100644 --- a/contrib/curl/lib/vauth/vauth.h +++ b/contrib/curl/lib/vauth/vauth.h @@ -24,7 +24,7 @@ #include -struct SessionHandle; +struct Curl_easy; #if !defined(CURL_DISABLE_CRYPTO_AUTH) struct digestdata; @@ -55,19 +55,22 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host, const char *realm); #endif +/* This is used to test if the user contains a Windows domain name */ +bool Curl_auth_user_contains_domain(const char *user); + /* This is used to generate a base64 encoded PLAIN cleartext message */ -CURLcode Curl_auth_create_plain_message(struct SessionHandle *data, +CURLcode Curl_auth_create_plain_message(struct Curl_easy *data, const char *userp, const char *passwdp, char **outptr, size_t *outlen); /* This is used to generate a base64 encoded LOGIN cleartext message */ -CURLcode Curl_auth_create_login_message(struct SessionHandle *data, +CURLcode Curl_auth_create_login_message(struct Curl_easy *data, const char *valuep, char **outptr, size_t *outlen); /* This is used to generate a base64 encoded EXTERNAL cleartext message */ -CURLcode Curl_auth_create_external_message(struct SessionHandle *data, +CURLcode Curl_auth_create_external_message(struct Curl_easy *data, const char *user, char **outptr, size_t *outlen); @@ -77,14 +80,17 @@ CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr, size_t *outlen); /* This is used to generate a CRAM-MD5 response message */ -CURLcode Curl_auth_create_cram_md5_message(struct SessionHandle *data, +CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data, const char *chlg, const char *userp, const char *passwdp, char **outptr, size_t *outlen); +/* This is used to evaluate if DIGEST is supported */ +bool Curl_auth_is_digest_supported(void); + /* This is used to generate a base64 encoded DIGEST-MD5 response message */ -CURLcode Curl_auth_create_digest_md5_message(struct SessionHandle *data, +CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, const char *chlg64, const char *userp, const char *passwdp, @@ -96,7 +102,7 @@ CURLcode Curl_auth_decode_digest_http_message(const char *chlg, struct digestdata *digest); /* This is used to generate a HTTP DIGEST response message */ -CURLcode Curl_auth_create_digest_http_message(struct SessionHandle *data, +CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, const char *userp, const char *passwdp, const unsigned char *request, @@ -109,6 +115,9 @@ void Curl_auth_digest_cleanup(struct digestdata *digest); #endif /* !CURL_DISABLE_CRYPTO_AUTH */ #if defined(USE_NTLM) +/* This is used to evaluate if NTLM is supported */ +bool Curl_auth_is_ntlm_supported(void); + /* This is used to generate a base64 encoded NTLM type-1 message */ CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, const char *passwdp, @@ -117,12 +126,12 @@ CURLcode Curl_auth_create_ntlm_type1_message(const char *userp, size_t *outlen); /* This is used to decode a base64 encoded NTLM type-2 message */ -CURLcode Curl_auth_decode_ntlm_type2_message(struct SessionHandle *data, +CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, const char *type2msg, struct ntlmdata *ntlm); /* This is used to generate a base64 encoded NTLM type-3 message */ -CURLcode Curl_auth_create_ntlm_type3_message(struct SessionHandle *data, +CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, const char *userp, const char *passwdp, struct ntlmdata *ntlm, @@ -133,16 +142,19 @@ void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm); #endif /* USE_NTLM */ /* This is used to generate a base64 encoded OAuth 2.0 message */ -CURLcode Curl_auth_create_oauth_bearer_message(struct SessionHandle *data, +CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data, const char *user, const char *host, const long port, const char *bearer, char **outptr, size_t *outlen); #if defined(USE_KERBEROS5) +/* This is used to evaluate if GSSAPI (Kerberos V5) is supported */ +bool Curl_auth_is_gssapi_supported(void); + /* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token message */ -CURLcode Curl_auth_create_gssapi_user_message(struct SessionHandle *data, +CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, const char *userp, const char *passwdp, const char *service, @@ -154,7 +166,7 @@ CURLcode Curl_auth_create_gssapi_user_message(struct SessionHandle *data, /* This is used to generate a base64 encoded GSSAPI (Kerberos V5) security token message */ -CURLcode Curl_auth_create_gssapi_security_message(struct SessionHandle *data, +CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, const char *input, struct kerberos5data *krb5, char **outptr, @@ -164,10 +176,13 @@ CURLcode Curl_auth_create_gssapi_security_message(struct SessionHandle *data, void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5); #endif /* USE_KERBEROS5 */ -#if (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) && defined(USE_SPNEGO) +#if defined(USE_SPNEGO) +/* This is used to evaluate if SPNEGO (Negotiate) is supported */ +bool Curl_auth_is_spnego_supported(void); + /* This is used to decode a base64 encoded SPNEGO (Negotiate) challenge message */ -CURLcode Curl_auth_decode_spnego_message(struct SessionHandle *data, +CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, const char *user, const char *passwood, const char *service, @@ -177,13 +192,13 @@ CURLcode Curl_auth_decode_spnego_message(struct SessionHandle *data, /* This is used to generate a base64 encoded SPNEGO (Negotiate) response message */ -CURLcode Curl_auth_create_spnego_message(struct SessionHandle *data, +CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data, struct negotiatedata *nego, char **outptr, size_t *outlen); /* This is used to clean up the SPNEGO specifiec data */ -void Curl_auth_spnego_cleanup(struct negotiatedata* nego); +void Curl_auth_spnego_cleanup(struct negotiatedata *nego); -#endif /* (HAVE_GSSAPI || USE_WINDOWS_SSPI) && USE_SPNEGO */ +#endif /* USE_SPNEGO */ #endif /* HEADER_CURL_VAUTH_H */ diff --git a/contrib/curl/lib/version.c b/contrib/curl/lib/version.c index 12924453..3d177681 100644 --- a/contrib/curl/lib/version.c +++ b/contrib/curl/lib/version.c @@ -36,8 +36,8 @@ # include #endif -#ifdef USE_LIBIDN -#include +#ifdef USE_LIBIDN2 +#include #endif #ifdef USE_LIBPSL @@ -111,9 +111,9 @@ char *curl_version(void) left -= len; ptr += len; #endif -#ifdef USE_LIBIDN - if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) { - len = snprintf(ptr, left, " libidn/%s", stringprep_check_version(NULL)); +#ifdef USE_LIBIDN2 + if(idn2_check_version(IDN2_VERSION)) { + len = snprintf(ptr, left, " libidn2/%s", idn2_check_version(NULL)); left -= len; ptr += len; } @@ -323,6 +323,9 @@ static curl_version_info_data version_info = { #endif #if defined(USE_LIBPSL) | CURL_VERSION_PSL +#endif +#if defined(HTTPS_PROXY_SUPPORT) + | CURL_VERSION_HTTPS_PROXY #endif , NULL, /* ssl_version */ @@ -365,10 +368,10 @@ curl_version_info_data *curl_version_info(CURLversion stamp) version_info.ares_num = aresnum; } #endif -#ifdef USE_LIBIDN +#ifdef USE_LIBIDN2 /* This returns a version string if we use the given version or later, otherwise it returns NULL */ - version_info.libidn = stringprep_check_version(LIBIDN_REQUIRED_VERSION); + version_info.libidn = idn2_check_version(IDN2_VERSION); if(version_info.libidn) version_info.features |= CURL_VERSION_IDN; #elif defined(USE_WIN32_IDN) diff --git a/contrib/curl/lib/vtls/axtls.c b/contrib/curl/lib/vtls/axtls.c index 0afcfaa5..1de758b0 100644 --- a/contrib/curl/lib/vtls/axtls.c +++ b/contrib/curl/lib/vtls/axtls.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2010, DirecTV, Contact: Eric Hu, . - * Copyright (C) 2010 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 2010 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -65,7 +65,7 @@ int Curl_axtls_cleanup(void) static CURLcode map_error_to_curl(int axtls_err) { - switch (axtls_err) { + switch(axtls_err) { case SSL_ERROR_NOT_SUPPORTED: case SSL_ERROR_INVALID_VERSION: case -70: /* protocol version alert from server */ @@ -121,7 +121,7 @@ static Curl_send axtls_send; static void free_ssl_structs(struct ssl_connect_data *connssl) { if(connssl->ssl) { - ssl_free (connssl->ssl); + ssl_free(connssl->ssl); connssl->ssl = NULL; } if(connssl->ssl_ctx) { @@ -137,14 +137,12 @@ static void free_ssl_structs(struct ssl_connect_data *connssl) */ static CURLcode connect_prep(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; SSL_CTX *ssl_ctx; SSL *ssl = NULL; int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0}; int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0}; int i, ssl_fcn_return; - const uint8_t *ssl_sessionid; - size_t ssl_idsize; /* Assuming users will not compile in custom key/cert to axTLS. * Also, even for blocking connects, use axTLS non-blocking feature. @@ -160,7 +158,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) /* axTLS only supports TLSv1 */ /* check to see if we've been told to use an explicit SSL/TLS version */ - switch(data->set.ssl.version) { + switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: break; @@ -185,17 +183,17 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) conn->ssl[sockindex].ssl = NULL; /* Load the trusted CA cert bundle file */ - if(data->set.ssl.CAfile) { - if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, data->set.ssl.CAfile, NULL) - != SSL_OK) { + if(SSL_CONN_CONFIG(CAfile)) { + if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, + SSL_CONN_CONFIG(CAfile), NULL) != SSL_OK) { infof(data, "error reading ca cert file %s \n", - data->set.ssl.CAfile); - if(data->set.ssl.verifypeer) { + SSL_CONN_CONFIG(CAfile)); + if(SSL_CONN_CONFIG(verifypeer)) { return CURLE_SSL_CACERT_BADFILE; } } else - infof(data, "found certificates in %s\n", data->set.ssl.CAfile); + infof(data, "found certificates in %s\n", SSL_CONN_CONFIG(CAfile)); } /* gtls.c tasks we're skipping for now: @@ -207,15 +205,15 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) */ /* Load client certificate */ - if(data->set.str[STRING_CERT]) { + if(SSL_SET_OPTION(cert)) { i=0; /* Instead of trying to analyze cert type here, let axTLS try them all. */ while(cert_types[i] != 0) { ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i], - data->set.str[STRING_CERT], NULL); + SSL_SET_OPTION(cert), NULL); if(ssl_fcn_return == SSL_OK) { infof(data, "successfully read cert file %s \n", - data->set.str[STRING_CERT]); + SSL_SET_OPTION(cert)); break; } i++; @@ -223,7 +221,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) /* Tried all cert types, none worked. */ if(cert_types[i] == 0) { failf(data, "%s is not x509 or pkcs12 format", - data->set.str[STRING_CERT]); + SSL_SET_OPTION(cert)); return CURLE_SSL_CERTPROBLEM; } } @@ -231,15 +229,15 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) /* Load client key. If a pkcs12 file successfully loaded a cert, then there's nothing to do because the key has already been loaded. */ - if(data->set.str[STRING_KEY] && cert_types[i] != SSL_OBJ_PKCS12) { + if(SSL_SET_OPTION(key) && cert_types[i] != SSL_OBJ_PKCS12) { i=0; /* Instead of trying to analyze key type here, let axTLS try them all. */ while(key_types[i] != 0) { ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i], - data->set.str[STRING_KEY], NULL); + SSL_SET_OPTION(key), NULL); if(ssl_fcn_return == SSL_OK) { infof(data, "successfully read key file %s \n", - data->set.str[STRING_KEY]); + SSL_SET_OPTION(key)); break; } i++; @@ -247,7 +245,7 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) /* Tried all key types, none worked. */ if(key_types[i] == 0) { failf(data, "Failure: %s is not a supported key file", - data->set.str[STRING_KEY]); + SSL_SET_OPTION(key)); return CURLE_SSL_CONNECT_ERROR; } } @@ -258,15 +256,24 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) * 2) setting up callbacks. these seem gnutls specific */ - /* In axTLS, handshaking happens inside ssl_client_new. */ - if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize)) { - /* we got a session id, use it! */ - infof (data, "SSL re-using session ID\n"); - ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], - ssl_sessionid, (uint8_t)ssl_idsize); + if(data->set.general_ssl.sessionid) { + const uint8_t *ssl_sessionid; + size_t ssl_idsize; + + /* In axTLS, handshaking happens inside ssl_client_new. */ + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize, + sockindex)) { + /* we got a session id, use it! */ + infof(data, "SSL re-using session ID\n"); + ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], + ssl_sessionid, (uint8_t)ssl_idsize, NULL); + } + Curl_ssl_sessionid_unlock(conn); } - else - ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0); + + if(!ssl) + ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0, NULL); conn->ssl[sockindex].ssl = ssl; return CURLE_OK; @@ -278,22 +285,24 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex) */ static CURLcode connect_finish(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; SSL *ssl = conn->ssl[sockindex].ssl; - const uint8_t *ssl_sessionid; - size_t ssl_idsize; const char *peer_CN; uint32_t dns_altname_index; const char *dns_altname; int8_t found_subject_alt_names = 0; int8_t found_subject_alt_name_matching_conn = 0; + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; + const char * const dispname = SSL_IS_PROXY() ? + conn->http_proxy.host.dispname : conn->host.dispname; /* Here, gtls.c gets the peer certificates and fails out depending on * settings in "data." axTLS api doesn't have get cert chain fcn, so omit? */ /* Verify server's certificate */ - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { if(ssl_verify_cert(ssl) != SSL_OK) { Curl_axtls_close(conn, sockindex); failf(data, "server cert verify failed"); @@ -324,8 +333,8 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex) found_subject_alt_names = 1; infof(data, "\tComparing subject alt name DNS with hostname: %s <-> %s\n", - dns_altname, conn->host.name); - if(Curl_cert_hostcheck(dns_altname, conn->host.name)) { + dns_altname, hostname); + if(Curl_cert_hostcheck(dns_altname, hostname)) { found_subject_alt_name_matching_conn = 1; break; } @@ -333,23 +342,21 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex) /* RFC2818 checks */ if(found_subject_alt_names && !found_subject_alt_name_matching_conn) { - if(data->set.ssl.verifyhost) { + if(SSL_CONN_CONFIG(verifyhost)) { /* Break connection ! */ Curl_axtls_close(conn, sockindex); - failf(data, "\tsubjectAltName(s) do not match %s\n", - conn->host.dispname); + failf(data, "\tsubjectAltName(s) do not match %s\n", dispname); return CURLE_PEER_FAILED_VERIFICATION; } else - infof(data, "\tsubjectAltName(s) do not match %s\n", - conn->host.dispname); + infof(data, "\tsubjectAltName(s) do not match %s\n", dispname); } else if(found_subject_alt_names == 0) { /* Per RFC2818, when no Subject Alt Names were available, examine the peer CN as a legacy fallback */ peer_CN = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME); if(peer_CN == NULL) { - if(data->set.ssl.verifyhost) { + if(SSL_CONN_CONFIG(verifyhost)) { Curl_axtls_close(conn, sockindex); failf(data, "unable to obtain common name from peer certificate"); return CURLE_PEER_FAILED_VERIFICATION; @@ -358,17 +365,17 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex) infof(data, "unable to obtain common name from peer certificate"); } else { - if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) { - if(data->set.ssl.verifyhost) { + if(!Curl_cert_hostcheck((const char *)peer_CN, hostname)) { + if(SSL_CONN_CONFIG(verifyhost)) { /* Break connection ! */ Curl_axtls_close(conn, sockindex); failf(data, "\tcommon name \"%s\" does not match \"%s\"\n", - peer_CN, conn->host.dispname); + peer_CN, dispname); return CURLE_PEER_FAILED_VERIFICATION; } else infof(data, "\tcommon name \"%s\" does not match \"%s\"\n", - peer_CN, conn->host.dispname); + peer_CN, dispname); } } } @@ -379,11 +386,15 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex) conn->send[sockindex] = axtls_send; /* Put our freshly minted SSL session in cache */ - ssl_idsize = ssl_get_session_id_size(ssl); - ssl_sessionid = ssl_get_session_id(ssl); - if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize) - != CURLE_OK) - infof (data, "failed to add session to cache\n"); + if(data->set.general_ssl.sessionid) { + const uint8_t *ssl_sessionid = ssl_get_session_id(ssl); + size_t ssl_idsize = ssl_get_session_id_size(ssl); + Curl_ssl_sessionid_lock(conn); + if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize, + sockindex) != CURLE_OK) + infof(data, "failed to add session to cache\n"); + Curl_ssl_sessionid_unlock(conn); + } return CURLE_OK; } @@ -429,7 +440,7 @@ CURLcode Curl_axtls_connect_nonblocking( return CURLE_OK; } } - infof (conn->data, "handshake completed successfully\n"); + infof(conn->data, "handshake completed successfully\n"); conn->ssl[sockindex].connecting_state = ssl_connect_3; } @@ -464,7 +475,7 @@ Curl_axtls_connect(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode conn_step = connect_prep(conn, sockindex); int ssl_fcn_return; SSL *ssl = conn->ssl[sockindex].ssl; @@ -493,9 +504,9 @@ Curl_axtls_connect(struct connectdata *conn, return map_error_to_curl(ssl_fcn_return); } /* TODO: avoid polling */ - usleep(10000); + Curl_wait_ms(10); } - infof (conn->data, "handshake completed successfully\n"); + infof(conn->data, "handshake completed successfully\n"); conn_step = connect_finish(conn, sockindex); if(conn_step != CURLE_OK) { @@ -554,7 +565,7 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) */ int retval = 0; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; uint8_t *buf; ssize_t nread; @@ -571,8 +582,7 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) */ if(connssl->ssl) { - int what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + int what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); if(what > 0) { /* Something to read, let's do it and hope that it is the close notify alert from the server. buf is managed internally by @@ -670,9 +680,9 @@ size_t Curl_axtls_version(char *buffer, size_t size) return snprintf(buffer, size, "axTLS/%s", ssl_version()); } -int Curl_axtls_random(struct SessionHandle *data, - unsigned char *entropy, - size_t length) +CURLcode Curl_axtls_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length) { static bool ssl_seeded = FALSE; (void)data; @@ -684,7 +694,7 @@ int Curl_axtls_random(struct SessionHandle *data, RNG_initialize(); } get_random((int)length, entropy); - return 0; + return CURLE_OK; } #endif /* USE_AXTLS */ diff --git a/contrib/curl/lib/vtls/axtls.h b/contrib/curl/lib/vtls/axtls.h index b9d441f1..53797ead 100644 --- a/contrib/curl/lib/vtls/axtls.h +++ b/contrib/curl/lib/vtls/axtls.h @@ -8,7 +8,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2010, DirecTV, Contact: Eric Hu - * Copyright (C) 2010 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2010 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -42,9 +42,9 @@ void Curl_axtls_session_free(void *ptr); size_t Curl_axtls_version(char *buffer, size_t size); int Curl_axtls_shutdown(struct connectdata *conn, int sockindex); int Curl_axtls_check_cxn(struct connectdata *conn); -int Curl_axtls_random(struct SessionHandle *data, - unsigned char *entropy, - size_t length); +CURLcode Curl_axtls_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length); /* Set the API backend definition to axTLS */ #define CURL_SSL_BACKEND CURLSSLBACKEND_AXTLS diff --git a/contrib/curl/lib/vtls/cyassl.c b/contrib/curl/lib/vtls/cyassl.c index da737c72..5e5947ce 100644 --- a/contrib/curl/lib/vtls/cyassl.c +++ b/contrib/curl/lib/vtls/cyassl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -55,7 +55,7 @@ and that's a problem since options.h hasn't been included yet. */ #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" -#include "rawstr.h" +#include "strcase.h" #include "x509asn1.h" #include "curl_printf.h" @@ -118,9 +118,9 @@ static int do_file_type(const char *type) { if(!type || !type[0]) return SSL_FILETYPE_PEM; - if(Curl_raw_equal(type, "PEM")) + if(strcasecompare(type, "PEM")) return SSL_FILETYPE_PEM; - if(Curl_raw_equal(type, "DER")) + if(strcasecompare(type, "DER")) return SSL_FILETYPE_ASN1; return -1; } @@ -134,10 +134,10 @@ cyassl_connect_step1(struct connectdata *conn, int sockindex) { char error_buffer[CYASSL_MAX_ERROR_SZ]; - struct SessionHandle *data = conn->data; + char *ciphers; + struct Curl_easy *data = conn->data; struct ssl_connect_data* conssl = &conn->ssl[sockindex]; SSL_METHOD* req_method = NULL; - void* ssl_sessionid = NULL; curl_socket_t sockfd = conn->sock[sockindex]; #ifdef HAVE_SNI bool sni = FALSE; @@ -150,7 +150,7 @@ cyassl_connect_step1(struct connectdata *conn, return CURLE_OK; /* check to see if we've been told to use an explicit SSL/TLS version */ - switch(data->set.ssl.version) { + switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: #if LIBCYASSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */ @@ -175,12 +175,15 @@ cyassl_connect_step1(struct connectdata *conn, req_method = TLSv1_2_client_method(); use_sni(TRUE); break; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "CyaSSL: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; case CURL_SSLVERSION_SSLv3: #ifdef WOLFSSL_ALLOW_SSLV3 req_method = SSLv3_client_method(); use_sni(FALSE); #else - failf(data, "No support for SSLv3"); + failf(data, "CyaSSL does not support SSLv3"); return CURLE_NOT_BUILT_IN; #endif break; @@ -206,7 +209,7 @@ cyassl_connect_step1(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } - switch(data->set.ssl.version) { + switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: #if LIBCYASSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */ @@ -227,20 +230,29 @@ cyassl_connect_step1(struct connectdata *conn, break; } + ciphers = SSL_CONN_CONFIG(cipher_list); + if(ciphers) { + if(!SSL_CTX_set_cipher_list(conssl->ctx, ciphers)) { + failf(data, "failed setting cipher list: %s", ciphers); + return CURLE_SSL_CIPHER; + } + infof(data, "Cipher selection: %s\n", ciphers); + } + #ifndef NO_FILESYSTEM /* load trusted cacert */ - if(data->set.str[STRING_SSL_CAFILE]) { + if(SSL_CONN_CONFIG(CAfile)) { if(1 != SSL_CTX_load_verify_locations(conssl->ctx, - data->set.str[STRING_SSL_CAFILE], - data->set.str[STRING_SSL_CAPATH])) { - if(data->set.ssl.verifypeer) { + SSL_CONN_CONFIG(CAfile), + SSL_CONN_CONFIG(CApath))) { + if(SSL_CONN_CONFIG(verifypeer)) { /* Fail if we insist on successfully verifying the server. */ failf(data, "error setting certificate verify locations:\n" " CAfile: %s\n CApath: %s", - data->set.str[STRING_SSL_CAFILE]? - data->set.str[STRING_SSL_CAFILE]: "none", - data->set.str[STRING_SSL_CAPATH]? - data->set.str[STRING_SSL_CAPATH] : "none"); + SSL_CONN_CONFIG(CAfile)? + SSL_CONN_CONFIG(CAfile): "none", + SSL_CONN_CONFIG(CApath)? + SSL_CONN_CONFIG(CApath) : "none"); return CURLE_SSL_CACERT_BADFILE; } else { @@ -257,25 +269,25 @@ cyassl_connect_step1(struct connectdata *conn, infof(data, " CAfile: %s\n" " CApath: %s\n", - data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]: + SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): "none", - data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]: + SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath): "none"); } /* Load the client certificate, and private key */ - if(data->set.str[STRING_CERT] && data->set.str[STRING_KEY]) { - int file_type = do_file_type(data->set.str[STRING_CERT_TYPE]); + if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) { + int file_type = do_file_type(SSL_SET_OPTION(cert_type)); - if(SSL_CTX_use_certificate_file(conssl->ctx, data->set.str[STRING_CERT], + if(SSL_CTX_use_certificate_file(conssl->ctx, SSL_SET_OPTION(cert), file_type) != 1) { failf(data, "unable to use client certificate (no key or wrong pass" " phrase?)"); return CURLE_SSL_CONNECT_ERROR; } - file_type = do_file_type(data->set.str[STRING_KEY_TYPE]); - if(SSL_CTX_use_PrivateKey_file(conssl->ctx, data->set.str[STRING_KEY], + file_type = do_file_type(SSL_SET_OPTION(key_type)); + if(SSL_CTX_use_PrivateKey_file(conssl->ctx, SSL_SET_OPTION(key), file_type) != 1) { failf(data, "unable to set private key"); return CURLE_SSL_CONNECT_ERROR; @@ -288,7 +300,8 @@ cyassl_connect_step1(struct connectdata *conn, * anyway. In the latter case the result of the verification is checked with * SSL_get_verify_result() below. */ SSL_CTX_set_verify(conssl->ctx, - data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE, + SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER: + SSL_VERIFY_NONE, NULL); #ifdef HAVE_SNI @@ -297,13 +310,15 @@ cyassl_connect_step1(struct connectdata *conn, #ifdef ENABLE_IPV6 struct in6_addr addr6; #endif - size_t hostname_len = strlen(conn->host.name); + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; + size_t hostname_len = strlen(hostname); if((hostname_len < USHRT_MAX) && - (0 == Curl_inet_pton(AF_INET, conn->host.name, &addr4)) && + (0 == Curl_inet_pton(AF_INET, hostname, &addr4)) && #ifdef ENABLE_IPV6 - (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr6)) && + (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) && #endif - (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, conn->host.name, + (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, hostname, (unsigned short)hostname_len) != 1)) { infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); @@ -332,7 +347,7 @@ cyassl_connect_step1(struct connectdata *conn, } } #ifdef NO_FILESYSTEM - else if(data->set.ssl.verifypeer) { + else if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "SSL: Certificates couldn't be loaded because CyaSSL was built" " with \"no filesystem\". Either disable peer verification" " (insecure) or if you are building an application with libcurl you" @@ -378,15 +393,23 @@ cyassl_connect_step1(struct connectdata *conn, #endif /* HAVE_ALPN */ /* Check if there's a cached ID we can/should use here! */ - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { - /* we got a session id, use it! */ - if(!SSL_set_session(conssl->handle, ssl_sessionid)) { - failf(data, "SSL: SSL_set_session failed: %s", - ERR_error_string(SSL_get_error(conssl->handle, 0), error_buffer)); - return CURLE_SSL_CONNECT_ERROR; + if(data->set.general_ssl.sessionid) { + void *ssl_sessionid = NULL; + + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { + /* we got a session id, use it! */ + if(!SSL_set_session(conssl->handle, ssl_sessionid)) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "SSL: SSL_set_session failed: %s", + ERR_error_string(SSL_get_error(conssl->handle, 0), + error_buffer)); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof(data, "SSL re-using session ID\n"); } - /* Informational message */ - infof (data, "SSL re-using session ID\n"); + Curl_ssl_sessionid_unlock(conn); } /* pass the raw socket into the SSL layer */ @@ -405,15 +428,22 @@ cyassl_connect_step2(struct connectdata *conn, int sockindex) { int ret = -1; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data* conssl = &conn->ssl[sockindex]; + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; + const char * const dispname = SSL_IS_PROXY() ? + conn->http_proxy.host.dispname : conn->host.dispname; + const char * const pinnedpubkey = SSL_IS_PROXY() ? + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : + data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; conn->recv[sockindex] = cyassl_recv; conn->send[sockindex] = cyassl_send; /* Enable RFC2818 checks */ - if(data->set.ssl.verifyhost) { - ret = CyaSSL_check_domain_name(conssl->handle, conn->host.name); + if(SSL_CONN_CONFIG(verifyhost)) { + ret = CyaSSL_check_domain_name(conssl->handle, hostname); if(ret == SSL_FAILURE) return CURLE_OUT_OF_MEMORY; } @@ -437,31 +467,31 @@ cyassl_connect_step2(struct connectdata *conn, else if(DOMAIN_NAME_MISMATCH == detail) { #if 1 failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n", - conn->host.dispname); + dispname); return CURLE_PEER_FAILED_VERIFICATION; #else /* When the CyaSSL_check_domain_name() is used and you desire to continue - * on a DOMAIN_NAME_MISMATCH, i.e. 'data->set.ssl.verifyhost == 0', + * on a DOMAIN_NAME_MISMATCH, i.e. 'conn->ssl_config.verifyhost == 0', * CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA error. The only * way to do this is currently to switch the CyaSSL_check_domain_name() - * in and out based on the 'data->set.ssl.verifyhost' value. */ - if(data->set.ssl.verifyhost) { + * in and out based on the 'conn->ssl_config.verifyhost' value. */ + if(SSL_CONN_CONFIG(verifyhost)) { failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n", - conn->host.dispname); + dispname); return CURLE_PEER_FAILED_VERIFICATION; } else { infof(data, "\tsubject alt name(s) and/or common name do not match \"%s\"\n", - conn->host.dispname); + dispname); return CURLE_OK; } #endif } #if LIBCYASSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */ else if(ASN_NO_SIGNER_E == detail) { - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "\tCA signer not available for verification\n"); return CURLE_SSL_CACERT_BADFILE; } @@ -480,7 +510,7 @@ cyassl_connect_step2(struct connectdata *conn, } } - if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { + if(pinnedpubkey) { #ifdef KEEP_PEER_CERT X509 *x509; const char *x509_der; @@ -502,7 +532,8 @@ cyassl_connect_step2(struct connectdata *conn, } memset(&x509_parsed, 0, sizeof x509_parsed); - Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len); + if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len)) + return CURLE_SSL_PINNEDPUBKEYNOTMATCH; pubkey = &x509_parsed.subjectPublicKeyInfo; if(!pubkey->header || pubkey->end <= pubkey->header) { @@ -511,7 +542,7 @@ cyassl_connect_step2(struct connectdata *conn, } result = Curl_pin_peer_pubkey(data, - data->set.str[STRING_SSL_PINNEDPUBLICKEY], + pinnedpubkey, (const unsigned char *)pubkey->header, (size_t)(pubkey->end - pubkey->header)); if(result) { @@ -560,7 +591,13 @@ cyassl_connect_step2(struct connectdata *conn, #endif /* HAVE_ALPN */ conssl->connecting_state = ssl_connect_3; +#if (LIBCYASSL_VERSION_HEX >= 0x03009010) + infof(data, "SSL connection using %s / %s\n", + wolfSSL_get_version(conssl->handle), + wolfSSL_get_cipher_name(conssl->handle)); +#else infof(data, "SSL connected\n"); +#endif return CURLE_OK; } @@ -571,32 +608,39 @@ cyassl_connect_step3(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; - void *old_ssl_sessionid=NULL; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - bool incache; - SSL_SESSION *our_ssl_sessionid; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - our_ssl_sessionid = SSL_get_session(connssl->handle); + if(data->set.general_ssl.sessionid) { + bool incache; + SSL_SESSION *our_ssl_sessionid; + void *old_ssl_sessionid = NULL; - incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); - if(incache) { - if(old_ssl_sessionid != our_ssl_sessionid) { - infof(data, "old SSL session ID is stale, removing\n"); - Curl_ssl_delsessionid(conn, old_ssl_sessionid); - incache = FALSE; - } - } + our_ssl_sessionid = SSL_get_session(connssl->handle); - if(!incache) { - result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */); - if(result) { - failf(data, "failed to store ssl session"); - return result; + Curl_ssl_sessionid_lock(conn); + incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, + sockindex)); + if(incache) { + if(old_ssl_sessionid != our_ssl_sessionid) { + infof(data, "old SSL session ID is stale, removing\n"); + Curl_ssl_delsessionid(conn, old_ssl_sessionid); + incache = FALSE; + } } + + if(!incache) { + result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, + 0 /* unknown size */, sockindex); + if(result) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "failed to store ssl session"); + return result; + } + } + Curl_ssl_sessionid_unlock(conn); } connssl->connecting_state = ssl_connect_done; @@ -641,11 +685,11 @@ void Curl_cyassl_close(struct connectdata *conn, int sockindex) if(conssl->handle) { (void)SSL_shutdown(conssl->handle); - SSL_free (conssl->handle); + SSL_free(conssl->handle); conssl->handle = NULL; } if(conssl->ctx) { - SSL_CTX_free (conssl->ctx); + SSL_CTX_free(conssl->ctx); conssl->ctx = NULL; } } @@ -727,7 +771,7 @@ int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex) struct ssl_connect_data *connssl = &conn->ssl[sockindex]; if(connssl->handle) { - SSL_free (connssl->handle); + SSL_free(connssl->handle); connssl->handle = NULL; } return retval; @@ -741,10 +785,10 @@ cyassl_connect_common(struct connectdata *conn, bool *done) { CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; - long timeout_ms; + time_t timeout_ms; int what; /* check if the connection has already been established */ @@ -790,7 +834,8 @@ cyassl_connect_common(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -872,19 +917,19 @@ Curl_cyassl_connect(struct connectdata *conn, return CURLE_OK; } -int Curl_cyassl_random(struct SessionHandle *data, - unsigned char *entropy, - size_t length) +CURLcode Curl_cyassl_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length) { RNG rng; (void)data; if(InitRng(&rng)) - return 1; + return CURLE_FAILED_INIT; if(length > UINT_MAX) - return 1; + return CURLE_FAILED_INIT; if(RNG_GenerateBlock(&rng, entropy, (unsigned)length)) - return 1; - return 0; + return CURLE_FAILED_INIT; + return CURLE_OK; } void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ diff --git a/contrib/curl/lib/vtls/cyassl.h b/contrib/curl/lib/vtls/cyassl.h index 11061255..f47719e4 100644 --- a/contrib/curl/lib/vtls/cyassl.h +++ b/contrib/curl/lib/vtls/cyassl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -51,15 +51,15 @@ int Curl_cyassl_init(void); CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done); -int Curl_cyassl_random(struct SessionHandle *data, - unsigned char *entropy, - size_t length); +CURLcode Curl_cyassl_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length); void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */ size_t tmplen, unsigned char *sha256sum, /* output */ size_t unused); -/* Set the API backend definition to Schannel */ +/* Set the API backend definition to CyaSSL */ #define CURL_SSL_BACKEND CURLSSLBACKEND_CYASSL /* this backend supports CURLOPT_SSL_CTX_* */ diff --git a/contrib/curl/lib/vtls/darwinssl.c b/contrib/curl/lib/vtls/darwinssl.c index 71d379b9..050bf960 100644 --- a/contrib/curl/lib/vtls/darwinssl.c +++ b/contrib/curl/lib/vtls/darwinssl.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2014, Nick Zitzmann, . - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -28,7 +28,7 @@ #include "curl_setup.h" -#include "urldata.h" /* for the SessionHandle definition */ +#include "urldata.h" /* for the Curl_easy definition */ #include "curl_base64.h" #include "strtok.h" @@ -197,7 +197,7 @@ static OSStatus SocketWrite(SSLConnectionRef connection, do { length = write(sock, - (char*)dataPtr + bytesSent, + (char *)dataPtr + bytesSent, dataLen - bytesSent); } while((length > 0) && ( (bytesSent += length) < dataLen) ); @@ -219,8 +219,10 @@ static OSStatus SocketWrite(SSLConnectionRef connection, return ortn; } -CF_INLINE const char *SSLCipherNameForNumber(SSLCipherSuite cipher) { - switch (cipher) { +#ifndef CURL_DISABLE_VERBOSE_STRINGS +CF_INLINE const char *SSLCipherNameForNumber(SSLCipherSuite cipher) +{ + switch(cipher) { /* SSL version 3.0 */ case SSL_RSA_WITH_NULL_MD5: return "SSL_RSA_WITH_NULL_MD5"; @@ -364,7 +366,8 @@ CF_INLINE const char *SSLCipherNameForNumber(SSLCipherSuite cipher) { return "SSL_NULL_WITH_NULL_NULL"; } -CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) { +CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) +{ switch(cipher) { /* TLS 1.0 with AES (RFC 3268) */ case TLS_RSA_WITH_AES_128_CBC_SHA: @@ -774,6 +777,7 @@ CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) { } return "TLS_NULL_WITH_NULL_NULL"; } +#endif /* !CURL_DISABLE_VERBOSE_STRINGS */ #if CURL_BUILD_MAC CF_INLINE void GetDarwinVersionNumber(int *major, int *minor) @@ -885,12 +889,17 @@ static OSStatus CopyIdentityWithLabel(char *label, OSStatus status = errSecItemNotFound; #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS + CFArrayRef keys_list; + CFIndex keys_list_count; + CFIndex i; + CFStringRef common_name; + /* SecItemCopyMatching() was introduced in iOS and Snow Leopard. kSecClassIdentity was introduced in Lion. If both exist, let's use them to find the certificate. */ if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) { - CFTypeRef keys[4]; - CFTypeRef values[4]; + CFTypeRef keys[5]; + CFTypeRef values[5]; CFDictionaryRef query_dict; CFStringRef label_cf = CFStringCreateWithCString(NULL, label, kCFStringEncodingUTF8); @@ -900,27 +909,66 @@ static OSStatus CopyIdentityWithLabel(char *label, keys[0] = kSecClass; values[1] = kCFBooleanTrue; /* we want a reference */ keys[1] = kSecReturnRef; - values[2] = kSecMatchLimitOne; /* one is enough, thanks */ + values[2] = kSecMatchLimitAll; /* kSecMatchLimitOne would be better if the + * label matching below worked correctly */ keys[2] = kSecMatchLimit; /* identity searches need a SecPolicyRef in order to work */ - values[3] = SecPolicyCreateSSL(false, label_cf); + values[3] = SecPolicyCreateSSL(false, NULL); keys[3] = kSecMatchPolicy; + /* match the name of the certificate (doesn't work in macOS 10.12.1) */ + values[4] = label_cf; + keys[4] = kSecAttrLabel; query_dict = CFDictionaryCreate(NULL, (const void **)keys, - (const void **)values, 4L, - &kCFCopyStringDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); + (const void **)values, 5L, + &kCFCopyStringDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); CFRelease(values[3]); - CFRelease(label_cf); /* Do we have a match? */ - status = SecItemCopyMatching(query_dict, (CFTypeRef *)out_cert_and_key); + status = SecItemCopyMatching(query_dict, (CFTypeRef *) &keys_list); + + /* Because kSecAttrLabel matching doesn't work with kSecClassIdentity, + * we need to find the correct identity ourselves */ + if(status == noErr) { + keys_list_count = CFArrayGetCount(keys_list); + *out_cert_and_key = NULL; + status = 1; + for(i=0; idata; + struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); + char * const ssl_cert = SSL_SET_OPTION(cert); + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; + const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; #ifdef ENABLE_IPV6 struct in6_addr addr; #else @@ -1009,8 +1063,6 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, #endif /* ENABLE_IPV6 */ size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i; SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL; - char *ssl_sessionid; - size_t ssl_sessionid_len; OSStatus err = noErr; #if CURL_BUILD_MAC int darwinver_maj = 0, darwinver_min = 0; @@ -1054,40 +1106,46 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, /* check to see if we've been told to use an explicit SSL/TLS version */ #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS if(SSLSetProtocolVersionMax != NULL) { - switch(data->set.ssl.version) { - default: - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1); - (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12); - break; - case CURL_SSLVERSION_TLSv1_0: - (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1); - (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol1); - break; - case CURL_SSLVERSION_TLSv1_1: - (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol11); - (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol11); - break; - case CURL_SSLVERSION_TLSv1_2: - (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol12); - (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12); - break; - case CURL_SSLVERSION_SSLv3: - err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3); - if(err != noErr) { - failf(data, "Your version of the OS does not support SSLv3"); - return CURLE_SSL_CONNECT_ERROR; - } - (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol3); - break; - case CURL_SSLVERSION_SSLv2: - err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol2); - if(err != noErr) { - failf(data, "Your version of the OS does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - } - (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol2); + switch(conn->ssl_config.version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1); + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12); + break; + case CURL_SSLVERSION_TLSv1_0: + (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1); + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol1); + break; + case CURL_SSLVERSION_TLSv1_1: + (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol11); + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol11); + break; + case CURL_SSLVERSION_TLSv1_2: + (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol12); + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12); + break; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "DarwinSSL: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_SSLv3: + err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3); + if(err != noErr) { + failf(data, "Your version of the OS does not support SSLv3"); + return CURLE_SSL_CONNECT_ERROR; + } + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol3); + break; + case CURL_SSLVERSION_SSLv2: + err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol2); + if(err != noErr) { + failf(data, "Your version of the OS does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + } + (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol2); + break; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; } } else { @@ -1095,82 +1153,37 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false); - switch (data->set.ssl.version) { - default: - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kTLSProtocol1, - true); - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kTLSProtocol11, - true); - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kTLSProtocol12, - true); - break; - case CURL_SSLVERSION_TLSv1_0: - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kTLSProtocol1, - true); - break; - case CURL_SSLVERSION_TLSv1_1: - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kTLSProtocol11, - true); - break; - case CURL_SSLVERSION_TLSv1_2: - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kTLSProtocol12, - true); - break; - case CURL_SSLVERSION_SSLv3: - err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kSSLProtocol3, - true); - if(err != noErr) { - failf(data, "Your version of the OS does not support SSLv3"); - return CURLE_SSL_CONNECT_ERROR; - } - break; - case CURL_SSLVERSION_SSLv2: - err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kSSLProtocol2, - true); - if(err != noErr) { - failf(data, "Your version of the OS does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - } - break; - } -#endif /* CURL_SUPPORT_MAC_10_8 */ - } -#else - (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false); - switch(data->set.ssl.version) { - default: + switch(conn->ssl_config.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol1, + true); + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol11, + true); + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol12, + true); + break; case CURL_SSLVERSION_TLSv1_0: (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kTLSProtocol1, true); break; case CURL_SSLVERSION_TLSv1_1: - failf(data, "Your version of the OS does not support TLSv1.1"); - return CURLE_SSL_CONNECT_ERROR; - case CURL_SSLVERSION_TLSv1_2: - failf(data, "Your version of the OS does not support TLSv1.2"); - return CURLE_SSL_CONNECT_ERROR; - case CURL_SSLVERSION_SSLv2: - err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, - kSSLProtocol2, + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol11, true); - if(err != noErr) { - failf(data, "Your version of the OS does not support SSLv2"); - return CURLE_SSL_CONNECT_ERROR; - } break; + case CURL_SSLVERSION_TLSv1_2: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol12, + true); + break; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "DarwinSSL: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; case CURL_SSLVERSION_SSLv3: err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocol3, @@ -1180,36 +1193,91 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, return CURLE_SSL_CONNECT_ERROR; } break; + case CURL_SSLVERSION_SSLv2: + err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kSSLProtocol2, + true); + if(err != noErr) { + failf(data, "Your version of the OS does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + } + break; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; + } +#endif /* CURL_SUPPORT_MAC_10_8 */ + } +#else + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false); + switch(conn->ssl_config.version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + case CURL_SSLVERSION_TLSv1_0: + (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kTLSProtocol1, + true); + break; + case CURL_SSLVERSION_TLSv1_1: + failf(data, "Your version of the OS does not support TLSv1.1"); + return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_TLSv1_2: + failf(data, "Your version of the OS does not support TLSv1.2"); + return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "Your version of the OS does not support TLSv1.3"); + return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_SSLv2: + err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kSSLProtocol2, + true); + if(err != noErr) { + failf(data, "Your version of the OS does not support SSLv2"); + return CURLE_SSL_CONNECT_ERROR; + } + break; + case CURL_SSLVERSION_SSLv3: + err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, + kSSLProtocol3, + true); + if(err != noErr) { + failf(data, "Your version of the OS does not support SSLv3"); + return CURLE_SSL_CONNECT_ERROR; + } + break; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; } #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ - if(data->set.str[STRING_KEY]) { + if(SSL_SET_OPTION(key)) { infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure " - "Transport. The private key must be in the Keychain.\n"); + "Transport. The private key must be in the Keychain.\n"); } - if(data->set.str[STRING_CERT]) { + if(ssl_cert) { SecIdentityRef cert_and_key = NULL; - bool is_cert_file = is_file(data->set.str[STRING_CERT]); + bool is_cert_file = is_file(ssl_cert); /* User wants to authenticate with a client cert. Look for it: If we detect that this is a file on disk, then let's load it. Otherwise, assume that the user wants to use an identity loaded from the Keychain. */ if(is_cert_file) { - if(!data->set.str[STRING_CERT_TYPE]) + if(!SSL_SET_OPTION(cert_type)) infof(data, "WARNING: SSL: Certificate type not set, assuming " "PKCS#12 format.\n"); - else if(strncmp(data->set.str[STRING_CERT_TYPE], "P12", - strlen(data->set.str[STRING_CERT_TYPE])) != 0) + else if(strncmp(SSL_SET_OPTION(cert_type), "P12", + strlen(SSL_SET_OPTION(cert_type))) != 0) infof(data, "WARNING: SSL: The Security framework only supports " "loading identities that are in PKCS#12 format.\n"); - err = CopyIdentityFromPKCS12File(data->set.str[STRING_CERT], - data->set.str[STRING_KEY_PASSWD], &cert_and_key); + err = CopyIdentityFromPKCS12File(ssl_cert, + SSL_SET_OPTION(key_passwd), &cert_and_key); } else - err = CopyIdentityWithLabel(data->set.str[STRING_CERT], &cert_and_key); + err = CopyIdentityWithLabel(ssl_cert, &cert_and_key); if(err == noErr) { SecCertificateRef cert = NULL; @@ -1248,27 +1316,27 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } else { switch(err) { - case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */ - failf(data, "SSL: Incorrect password for the certificate \"%s\" " - "and its private key.", data->set.str[STRING_CERT]); - break; - case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */ - failf(data, "SSL: Couldn't make sense of the data in the " - "certificate \"%s\" and its private key.", - data->set.str[STRING_CERT]); - break; - case -25260: /* errSecPassphraseRequired */ - failf(data, "SSL The certificate \"%s\" requires a password.", - data->set.str[STRING_CERT]); - break; - case errSecItemNotFound: - failf(data, "SSL: Can't find the certificate \"%s\" and its private " - "key in the Keychain.", data->set.str[STRING_CERT]); - break; - default: - failf(data, "SSL: Can't load the certificate \"%s\" and its private " - "key: OSStatus %d", data->set.str[STRING_CERT], err); - break; + case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */ + failf(data, "SSL: Incorrect password for the certificate \"%s\" " + "and its private key.", ssl_cert); + break; + case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */ + failf(data, "SSL: Couldn't make sense of the data in the " + "certificate \"%s\" and its private key.", + ssl_cert); + break; + case -25260: /* errSecPassphraseRequired */ + failf(data, "SSL The certificate \"%s\" requires a password.", + ssl_cert); + break; + case errSecItemNotFound: + failf(data, "SSL: Can't find the certificate \"%s\" and its private " + "key in the Keychain.", ssl_cert); + break; + default: + failf(data, "SSL: Can't load the certificate \"%s\" and its private " + "key: OSStatus %d", ssl_cert, err); + break; } return CURLE_SSL_CERTPROBLEM; } @@ -1299,8 +1367,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, #else if(SSLSetSessionOption != NULL) { #endif /* CURL_BUILD_MAC */ - bool break_on_auth = !data->set.ssl.verifypeer || - data->set.str[STRING_SSL_CAFILE]; + bool break_on_auth = !conn->ssl_config.verifypeer || ssl_cafile; err = SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionBreakOnServerAuth, break_on_auth); @@ -1312,7 +1379,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, else { #if CURL_SUPPORT_MAC_10_8 err = SSLSetEnableCertVerify(connssl->ssl_ctx, - data->set.ssl.verifypeer?true:false); + conn->ssl_config.verifypeer?true:false); if(err != noErr) { failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); return CURLE_SSL_CONNECT_ERROR; @@ -1321,47 +1388,41 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, } #else err = SSLSetEnableCertVerify(connssl->ssl_ctx, - data->set.ssl.verifypeer?true:false); + conn->ssl_config.verifypeer?true:false); if(err != noErr) { failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); return CURLE_SSL_CONNECT_ERROR; } #endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */ - if(data->set.str[STRING_SSL_CAFILE]) { - bool is_cert_file = is_file(data->set.str[STRING_SSL_CAFILE]); + if(ssl_cafile && verifypeer) { + bool is_cert_file = is_file(ssl_cafile); if(!is_cert_file) { - failf(data, "SSL: can't load CA certificate file %s", - data->set.str[STRING_SSL_CAFILE]); + failf(data, "SSL: can't load CA certificate file %s", ssl_cafile); return CURLE_SSL_CACERT_BADFILE; } - if(!data->set.ssl.verifypeer) { - failf(data, "SSL: CA certificate set, but certificate verification " - "is disabled"); - return CURLE_SSL_CONNECT_ERROR; - } } /* Configure hostname check. SNI is used if available. * Both hostname check and SNI require SSLSetPeerDomainName(). * Also: the verifyhost setting influences SNI usage */ - if(data->set.ssl.verifyhost) { - err = SSLSetPeerDomainName(connssl->ssl_ctx, conn->host.name, - strlen(conn->host.name)); + if(conn->ssl_config.verifyhost) { + err = SSLSetPeerDomainName(connssl->ssl_ctx, hostname, + strlen(hostname)); if(err != noErr) { infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d\n", err); } - if((Curl_inet_pton(AF_INET, conn->host.name, &addr)) + if((Curl_inet_pton(AF_INET, hostname, &addr)) #ifdef ENABLE_IPV6 - || (Curl_inet_pton(AF_INET6, conn->host.name, &addr)) + || (Curl_inet_pton(AF_INET6, hostname, &addr)) #endif ) { - infof(data, "WARNING: using IP address, SNI is being disabled by " - "the OS.\n"); + infof(data, "WARNING: using IP address, SNI is being disabled by " + "the OS.\n"); } } @@ -1384,7 +1445,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, running in an affected version of OS X. */ if(darwinver_maj == 12 && darwinver_min <= 3 && all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) { - continue; + continue; } #endif /* CURL_BUILD_MAC */ switch(all_ciphers[i]) { @@ -1440,6 +1501,16 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, /* Disable IDEA: */ case SSL_RSA_WITH_IDEA_CBC_SHA: case SSL_RSA_WITH_IDEA_CBC_MD5: + /* Disable RC4: */ + case SSL_RSA_WITH_RC4_128_MD5: + case SSL_RSA_WITH_RC4_128_SHA: + case 0xC002: /* TLS_ECDH_ECDSA_WITH_RC4_128_SHA */ + case 0xC007: /* TLS_ECDHE_ECDSA_WITH_RC4_128_SHA*/ + case 0xC00C: /* TLS_ECDH_RSA_WITH_RC4_128_SHA */ + case 0xC011: /* TLS_ECDHE_RSA_WITH_RC4_128_SHA */ + case 0x008A: /* TLS_PSK_WITH_RC4_128_SHA */ + case 0x008E: /* TLS_DHE_PSK_WITH_RC4_128_SHA */ + case 0x0092: /* TLS_RSA_PSK_WITH_RC4_128_SHA */ break; default: /* enable everything else */ allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i]; @@ -1466,45 +1537,55 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, /* We want to enable 1/n-1 when using a CBC cipher unless the user specifically doesn't want us doing that: */ if(SSLSetSessionOption != NULL) { + /* TODO s/data->set.ssl.enable_beast/SSL_SET_OPTION(enable_beast)/g */ SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionSendOneByteRecord, - !data->set.ssl_enable_beast); + !data->set.ssl.enable_beast); SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionFalseStart, data->set.ssl.falsestart); /* false start support */ } #endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */ /* Check if there's a cached ID we can/should use here! */ - if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid, - &ssl_sessionid_len)) { - /* we got a session id, use it! */ - err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len); - if(err != noErr) { - failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; - } - /* Informational message */ - infof(data, "SSL re-using session ID\n"); - } - /* If there isn't one, then let's make one up! This has to be done prior - to starting the handshake. */ - else { - CURLcode result; - ssl_sessionid = - aprintf("%s:%d:%d:%s:%hu", data->set.str[STRING_SSL_CAFILE], - data->set.ssl.verifypeer, data->set.ssl.verifyhost, - conn->host.name, conn->remote_port); - ssl_sessionid_len = strlen(ssl_sessionid); + if(data->set.general_ssl.sessionid) { + char *ssl_sessionid; + size_t ssl_sessionid_len; - err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len); - if(err != noErr) { - failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); - return CURLE_SSL_CONNECT_ERROR; + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid, + &ssl_sessionid_len, sockindex)) { + /* we got a session id, use it! */ + err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len); + Curl_ssl_sessionid_unlock(conn); + if(err != noErr) { + failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof(data, "SSL re-using session ID\n"); } + /* If there isn't one, then let's make one up! This has to be done prior + to starting the handshake. */ + else { + CURLcode result; + ssl_sessionid = + aprintf("%s:%d:%d:%s:%hu", ssl_cafile, + verifypeer, SSL_CONN_CONFIG(verifyhost), hostname, port); + ssl_sessionid_len = strlen(ssl_sessionid); - result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len); - if(result) { - failf(data, "failed to store ssl session"); - return result; + err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len); + if(err != noErr) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); + return CURLE_SSL_CONNECT_ERROR; + } + + result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len, + sockindex); + Curl_ssl_sessionid_unlock(conn); + if(result) { + failf(data, "failed to store ssl session"); + return result; + } } } @@ -1626,7 +1707,7 @@ static int read_cert(const char *file, unsigned char **out, size_t *outlen) return 0; } -static int sslerr_to_curlerr(struct SessionHandle *data, int err) +static int sslerr_to_curlerr(struct Curl_easy *data, int err) { switch(err) { case errSSLXCertChainInvalid: @@ -1655,7 +1736,7 @@ static int sslerr_to_curlerr(struct SessionHandle *data, int err) } } -static int append_cert_to_array(struct SessionHandle *data, +static int append_cert_to_array(struct Curl_easy *data, unsigned char *buf, size_t buflen, CFMutableArrayRef array) { @@ -1700,7 +1781,7 @@ static int append_cert_to_array(struct SessionHandle *data, return CURLE_OK; } -static int verify_cert(const char *cafile, struct SessionHandle *data, +static int verify_cert(const char *cafile, struct Curl_easy *data, SSLContextRef ctx) { int n = 0, rc; @@ -1803,7 +1884,7 @@ static int verify_cert(const char *cafile, struct SessionHandle *data, return sslerr_to_curlerr(data, ret); } - switch (trust_eval) { + switch(trust_eval) { case kSecTrustResultUnspecified: case kSecTrustResultProceed: return CURLE_OK; @@ -1820,11 +1901,13 @@ static int verify_cert(const char *cafile, struct SessionHandle *data, static CURLcode darwinssl_connect_step2(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; OSStatus err; SSLCipherSuite cipher; SSLProtocol protocol = 0; + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; DEBUGASSERT(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state @@ -1834,7 +1917,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) err = SSLHandshake(connssl->ssl_ctx); if(err != noErr) { - switch (err) { + switch(err) { case errSSLWouldBlock: /* they're not done with us yet */ connssl->connecting_state = connssl->ssl_direction ? ssl_connect_2_writing : ssl_connect_2_reading; @@ -1843,8 +1926,8 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) /* The below is errSSLServerAuthCompleted; it's not defined in Leopard's headers */ case -9841: - if(data->set.str[STRING_SSL_CAFILE]) { - int res = verify_cert(data->set.str[STRING_SSL_CAFILE], data, + if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) { + int res = verify_cert(SSL_CONN_CONFIG(CAfile), data, connssl->ssl_ctx); if(res != CURLE_OK) return res; @@ -1913,7 +1996,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) return CURLE_SSL_CONNECT_ERROR; default: failf(data, "Unknown SSL protocol error in connection to %s:%d", - conn->host.name, err); + hostname, err); return CURLE_SSL_CONNECT_ERROR; } } @@ -1924,7 +2007,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) /* Informational message */ (void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher); (void)SSLGetNegotiatedProtocolVersion(connssl->ssl_ctx, &protocol); - switch (protocol) { + switch(protocol) { case kSSLProtocol2: infof(data, "SSL 2.0 connection using %s\n", SSLCipherNameForNumber(cipher)); @@ -1956,11 +2039,13 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) } } -static CURLcode -darwinssl_connect_step3(struct connectdata *conn, - int sockindex) +#ifndef CURL_DISABLE_VERBOSE_STRINGS +/* This should be called during step3 of the connection at the earliest */ +static void +show_verbose_server_cert(struct connectdata *conn, + int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CFStringRef server_cert_summary; char server_cert_summary_c[128]; @@ -1970,9 +2055,9 @@ darwinssl_connect_step3(struct connectdata *conn, CFIndex i, count; SecTrustRef trust = NULL; - /* There is no step 3! - * Well, okay, if verbose mode is on, let's print the details of the - * server certificates. */ + if(!connssl->ssl_ctx) + return; + #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS #if CURL_BUILD_IOS #pragma unused(server_certs) @@ -2069,6 +2154,23 @@ darwinssl_connect_step3(struct connectdata *conn, CFRelease(server_certs); } #endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ +} +#endif /* !CURL_DISABLE_VERBOSE_STRINGS */ + +static CURLcode +darwinssl_connect_step3(struct connectdata *conn, + int sockindex) +{ + struct Curl_easy *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + /* There is no step 3! + * Well, okay, if verbose mode is on, let's print the details of the + * server certificates. */ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(data->set.verbose) + show_verbose_server_cert(conn, sockindex); +#endif connssl->connecting_state = ssl_connect_done; return CURLE_OK; @@ -2084,7 +2186,7 @@ darwinssl_connect_common(struct connectdata *conn, bool *done) { CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; long timeout_ms; @@ -2133,7 +2235,8 @@ darwinssl_connect_common(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -2239,7 +2342,7 @@ void Curl_darwinssl_close(struct connectdata *conn, int sockindex) int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; ssize_t nread; int what; int rc; @@ -2255,8 +2358,7 @@ int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) rc = 0; - what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT); for(;;) { if(what < 0) { @@ -2284,7 +2386,7 @@ int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) if(nread <= 0) break; - what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0); + what = SOCKET_READABLE(conn->sock[sockindex], 0); } return rc; @@ -2346,8 +2448,8 @@ bool Curl_darwinssl_data_pending(const struct connectdata *conn, return false; } -int Curl_darwinssl_random(unsigned char *entropy, - size_t length) +CURLcode Curl_darwinssl_random(unsigned char *entropy, + size_t length) { /* arc4random_buf() isn't available on cats older than Lion, so let's do this manually for the benefit of the older cats. */ @@ -2361,7 +2463,7 @@ int Curl_darwinssl_random(unsigned char *entropy, random_number >>= 8; } i = random_number = 0; - return 0; + return CURLE_OK; } void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ @@ -2373,7 +2475,8 @@ void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ (void)CC_MD5(tmp, (CC_LONG)tmplen, md5sum); } -bool Curl_darwinssl_false_start(void) { +bool Curl_darwinssl_false_start(void) +{ #if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 if(SSLSetSessionOption != NULL) return TRUE; @@ -2387,7 +2490,7 @@ static ssize_t darwinssl_send(struct connectdata *conn, size_t len, CURLcode *curlcode) { - /*struct SessionHandle *data = conn->data;*/ + /*struct Curl_easy *data = conn->data;*/ struct ssl_connect_data *connssl = &conn->ssl[sockindex]; size_t processed = 0UL; OSStatus err; @@ -2410,7 +2513,7 @@ static ssize_t darwinssl_send(struct connectdata *conn, if(connssl->ssl_write_buffered_length) { /* Write the buffered data: */ err = SSLWrite(connssl->ssl_ctx, NULL, 0UL, &processed); - switch (err) { + switch(err) { case noErr: /* processed is always going to be 0 because we didn't write to the buffer, so return how much was written to the socket */ @@ -2430,7 +2533,7 @@ static ssize_t darwinssl_send(struct connectdata *conn, /* We've got new data to write: */ err = SSLWrite(connssl->ssl_ctx, mem, len, &processed); if(err != noErr) { - switch (err) { + switch(err) { case errSSLWouldBlock: /* Data was buffered but not sent, we have to tell the caller to try sending again, and remember how much was buffered */ @@ -2453,13 +2556,13 @@ static ssize_t darwinssl_recv(struct connectdata *conn, size_t buffersize, CURLcode *curlcode) { - /*struct SessionHandle *data = conn->data;*/ + /*struct Curl_easy *data = conn->data;*/ struct ssl_connect_data *connssl = &conn->ssl[num]; size_t processed = 0UL; OSStatus err = SSLRead(connssl->ssl_ctx, buf, buffersize, &processed); if(err != noErr) { - switch (err) { + switch(err) { case errSSLWouldBlock: /* return how much we read (if anything) */ if(processed) return (ssize_t)processed; diff --git a/contrib/curl/lib/vtls/darwinssl.h b/contrib/curl/lib/vtls/darwinssl.h index 8b185b67..4bd41ca4 100644 --- a/contrib/curl/lib/vtls/darwinssl.h +++ b/contrib/curl/lib/vtls/darwinssl.h @@ -8,7 +8,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012 - 2014, Nick Zitzmann, . - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -42,8 +42,8 @@ int Curl_darwinssl_check_cxn(struct connectdata *conn); bool Curl_darwinssl_data_pending(const struct connectdata *conn, int connindex); -int Curl_darwinssl_random(unsigned char *entropy, - size_t length); +CURLcode Curl_darwinssl_random(unsigned char *entropy, + size_t length); void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum, /* output */ diff --git a/contrib/curl/lib/vtls/gskit.c b/contrib/curl/lib/vtls/gskit.c index a9a8a918..a0d462b7 100644 --- a/contrib/curl/lib/vtls/gskit.c +++ b/contrib/curl/lib/vtls/gskit.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -72,7 +72,7 @@ #include "vtls.h" #include "connect.h" /* for the connect timeout */ #include "select.h" -#include "strequal.h" +#include "strcase.h" #include "x509asn1.h" #include "curl_printf.h" @@ -81,6 +81,10 @@ #include "memdebug.h" +/* Directions. */ +#define SOS_READ 0x01 +#define SOS_WRITE 0x02 + /* SSL version flags. */ #define CURL_GSKPROTO_SSLV2 0 #define CURL_GSKPROTO_SSLV2_MASK (1 << CURL_GSKPROTO_SSLV2) @@ -151,7 +155,7 @@ static const gskit_cipher ciphertable[] = { static bool is_separator(char c) { /* Return whether character is a cipher list separator. */ - switch (c) { + switch(c) { case ' ': case '\t': case ':': @@ -163,11 +167,11 @@ static bool is_separator(char c) } -static CURLcode gskit_status(struct SessionHandle *data, int rc, +static CURLcode gskit_status(struct Curl_easy *data, int rc, const char *procname, CURLcode defcode) { /* Process GSKit status and map it to a CURLcode. */ - switch (rc) { + switch(rc) { case GSK_OK: case GSK_OS400_ASYNCHRONOUS_SOC_INIT: return CURLE_OK; @@ -190,7 +194,7 @@ static CURLcode gskit_status(struct SessionHandle *data, int rc, case GSK_OS400_ERROR_NOT_REGISTERED: break; case GSK_ERROR_IO: - switch (errno) { + switch(errno) { case ENOMEM: return CURLE_OUT_OF_MEMORY; default: @@ -206,12 +210,12 @@ static CURLcode gskit_status(struct SessionHandle *data, int rc, } -static CURLcode set_enum(struct SessionHandle *data, gsk_handle h, +static CURLcode set_enum(struct Curl_easy *data, gsk_handle h, GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok) { int rc = gsk_attribute_set_enum(h, id, value); - switch (rc) { + switch(rc) { case GSK_OK: return CURLE_OK; case GSK_ERROR_IO: @@ -228,12 +232,12 @@ static CURLcode set_enum(struct SessionHandle *data, gsk_handle h, } -static CURLcode set_buffer(struct SessionHandle *data, gsk_handle h, +static CURLcode set_buffer(struct Curl_easy *data, gsk_handle h, GSK_BUF_ID id, const char *buffer, bool unsupported_ok) { int rc = gsk_attribute_set_buffer(h, id, buffer, 0); - switch (rc) { + switch(rc) { case GSK_OK: return CURLE_OK; case GSK_ERROR_IO: @@ -250,12 +254,12 @@ static CURLcode set_buffer(struct SessionHandle *data, gsk_handle h, } -static CURLcode set_numeric(struct SessionHandle *data, +static CURLcode set_numeric(struct Curl_easy *data, gsk_handle h, GSK_NUM_ID id, int value) { int rc = gsk_attribute_set_numeric_value(h, id, value); - switch (rc) { + switch(rc) { case GSK_OK: return CURLE_OK; case GSK_ERROR_IO: @@ -270,12 +274,12 @@ static CURLcode set_numeric(struct SessionHandle *data, } -static CURLcode set_callback(struct SessionHandle *data, +static CURLcode set_callback(struct Curl_easy *data, gsk_handle h, GSK_CALLBACK_ID id, void *info) { int rc = gsk_attribute_set_callback(h, id, info); - switch (rc) { + switch(rc) { case GSK_OK: return CURLE_OK; case GSK_ERROR_IO: @@ -289,10 +293,11 @@ static CURLcode set_callback(struct SessionHandle *data, } -static CURLcode set_ciphers(struct SessionHandle *data, +static CURLcode set_ciphers(struct connectdata *conn, gsk_handle h, unsigned int *protoflags) { - const char *cipherlist = data->set.str[STRING_SSL_CIPHER_LIST]; + struct Curl_easy *data = conn->data; + const char *cipherlist = SSL_CONN_CONFIG(cipher_list); const char *clp; const gskit_cipher *ctp; int i; @@ -340,7 +345,7 @@ static CURLcode set_ciphers(struct SessionHandle *data, break; /* Search the cipher in our table. */ for(ctp = ciphertable; ctp->name; ctp++) - if(strnequal(ctp->name, clp, l) && !ctp->name[l]) + if(strncasecompare(ctp->name, clp, l) && !ctp->name[l]) break; if(!ctp->name) { failf(data, "Unknown cipher %.*s", l, clp); @@ -436,7 +441,7 @@ void Curl_gskit_cleanup(void) } -static CURLcode init_environment(struct SessionHandle *data, +static CURLcode init_environment(struct Curl_easy *data, gsk_handle *envir, const char *appid, const char *file, const char *label, const char *password) @@ -448,7 +453,7 @@ static CURLcode init_environment(struct SessionHandle *data, /* Creates the GSKit environment. */ rc = gsk_environment_open(&h); - switch (rc) { + switch(rc) { case GSK_OK: break; case GSK_INSUFFICIENT_STORAGE: @@ -500,31 +505,214 @@ static void close_async_handshake(struct ssl_connect_data *connssl) connssl->iocport = -1; } +/* SSL over SSL + * Problems: + * 1) GSKit can only perform SSL on an AF_INET or AF_INET6 stream socket. To + * pipe an SSL stream into another, it is therefore needed to have a pair + * of such communicating sockets and handle the pipelining explicitly. + * 2) OS/400 socketpair() is only implemented for domain AF_UNIX, thus cannot + * be used to produce the pipeline. + * The solution is to simulate socketpair() for AF_INET with low-level API + * listen(), bind() and connect(). + */ -static void close_one(struct ssl_connect_data *conn, - struct SessionHandle *data) +static int +inetsocketpair(int sv[2]) { - if(conn->handle) { - gskit_status(data, gsk_secure_soc_close(&conn->handle), - "gsk_secure_soc_close()", 0); - conn->handle = (gsk_handle) NULL; + int lfd; /* Listening socket. */ + int sfd; /* Server socket. */ + int cfd; /* Client socket. */ + int len; + struct sockaddr_in addr1; + struct sockaddr_in addr2; + + /* Create listening socket on a local dynamic port. */ + lfd = socket(AF_INET, SOCK_STREAM, 0); + if(lfd < 0) + return -1; + memset((char *) &addr1, 0, sizeof addr1); + addr1.sin_family = AF_INET; + addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr1.sin_port = 0; + if(bind(lfd, (struct sockaddr *) &addr1, sizeof addr1) || + listen(lfd, 2) < 0) { + close(lfd); + return -1; } - if(conn->iocport >= 0) - close_async_handshake(conn); + + /* Get the allocated port. */ + len = sizeof addr1; + if(getsockname(lfd, (struct sockaddr *) &addr1, &len) < 0) { + close(lfd); + return -1; + } + + /* Create the client socket. */ + cfd = socket(AF_INET, SOCK_STREAM, 0); + if(cfd < 0) { + close(lfd); + return -1; + } + + /* Request unblocking connection to the listening socket. */ + curlx_nonblock(cfd, TRUE); + if(connect(cfd, (struct sockaddr *) &addr1, sizeof addr1) < 0 && + errno != EINPROGRESS) { + close(lfd); + close(cfd); + return -1; + } + + /* Get the client dynamic port for intrusion check below. */ + len = sizeof addr2; + if(getsockname(cfd, (struct sockaddr *) &addr2, &len) < 0) { + close(lfd); + close(cfd); + return -1; + } + + /* Accept the incoming connection and get the server socket. */ + curlx_nonblock(lfd, TRUE); + for(;;) { + len = sizeof addr1; + sfd = accept(lfd, (struct sockaddr *) &addr1, &len); + if(sfd < 0) { + close(lfd); + close(cfd); + return -1; + } + + /* Check for possible intrusion from an external process. */ + if(addr1.sin_addr.s_addr == addr2.sin_addr.s_addr && + addr1.sin_port == addr2.sin_port) + break; + + /* Intrusion: reject incoming connection. */ + close(sfd); + } + + /* Done, return sockets and succeed. */ + close(lfd); + curlx_nonblock(cfd, FALSE); + sv[0] = cfd; + sv[1] = sfd; + return 0; +} + +static int pipe_ssloverssl(struct connectdata *conn, int sockindex, + int directions) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_connect_data *connproxyssl = &conn->proxy_ssl[sockindex]; + fd_set fds_read; + fd_set fds_write; + int n; + int m; + int i; + int ret = 0; + struct timeval tv = {0, 0}; + char buf[CURL_MAX_WRITE_SIZE]; + + if(!connssl->use || !connproxyssl->use) + return 0; /* No SSL over SSL: OK. */ + + FD_ZERO(&fds_read); + FD_ZERO(&fds_write); + n = -1; + if(directions & SOS_READ) { + FD_SET(connssl->remotefd, &fds_write); + n = connssl->remotefd; + } + if(directions & SOS_WRITE) { + FD_SET(connssl->remotefd, &fds_read); + n = connssl->remotefd; + FD_SET(conn->sock[sockindex], &fds_write); + if(n < conn->sock[sockindex]) + n = conn->sock[sockindex]; + } + i = select(n + 1, &fds_read, &fds_write, NULL, &tv); + if(i < 0) + return -1; /* Select error. */ + + if(FD_ISSET(connssl->remotefd, &fds_write)) { + /* Try getting data from HTTPS proxy and pipe it upstream. */ + n = 0; + i = gsk_secure_soc_read(connproxyssl->handle, buf, sizeof buf, &n); + switch(i) { + case GSK_OK: + if(n) { + i = write(connssl->remotefd, buf, n); + if(i < 0) + return -1; + ret = 1; + } + break; + case GSK_OS400_ERROR_TIMED_OUT: + case GSK_WOULD_BLOCK: + break; + default: + return -1; + } + } + + if(FD_ISSET(connssl->remotefd, &fds_read) && + FD_ISSET(conn->sock[sockindex], &fds_write)) { + /* Pipe data to HTTPS proxy. */ + n = read(connssl->remotefd, buf, sizeof buf); + if(n < 0) + return -1; + if(n) { + i = gsk_secure_soc_write(connproxyssl->handle, buf, n, &m); + if(i != GSK_OK || n != m) + return -1; + ret = 1; + } + } + + return ret; /* OK */ +} + + +static void close_one(struct ssl_connect_data *connssl, + struct connectdata *conn, int sockindex) +{ + if(connssl->handle) { + gskit_status(conn->data, gsk_secure_soc_close(&connssl->handle), + "gsk_secure_soc_close()", 0); + /* Last chance to drain output. */ + while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0) + ; + connssl->handle = (gsk_handle) NULL; + if(connssl->localfd >= 0) { + close(connssl->localfd); + connssl->localfd = -1; + } + if(connssl->remotefd >= 0) { + close(connssl->remotefd); + connssl->remotefd = -1; + } + } + if(connssl->iocport >= 0) + close_async_handshake(connssl); } static ssize_t gskit_send(struct connectdata *conn, int sockindex, const void *mem, size_t len, CURLcode *curlcode) { - struct SessionHandle *data = conn->data; - CURLcode cc; + struct Curl_easy *data = conn->data; + CURLcode cc = CURLE_SEND_ERROR; int written; - cc = gskit_status(data, - gsk_secure_soc_write(conn->ssl[sockindex].handle, - (char *) mem, (int) len, &written), - "gsk_secure_soc_write()", CURLE_SEND_ERROR); + if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) >= 0) { + cc = gskit_status(data, + gsk_secure_soc_write(conn->ssl[sockindex].handle, + (char *) mem, (int) len, &written), + "gsk_secure_soc_write()", CURLE_SEND_ERROR); + if(cc == CURLE_OK) + if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) < 0) + cc = CURLE_SEND_ERROR; + } if(cc != CURLE_OK) { *curlcode = cc; written = -1; @@ -536,18 +724,26 @@ static ssize_t gskit_send(struct connectdata *conn, int sockindex, static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf, size_t buffersize, CURLcode *curlcode) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int buffsize; int nread; - CURLcode cc; + CURLcode cc = CURLE_RECV_ERROR; - buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize; - cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle, - buf, buffsize, &nread), - "gsk_secure_soc_read()", CURLE_RECV_ERROR); - if(cc != CURLE_OK) { + if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) { + buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize; + cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle, + buf, buffsize, &nread), + "gsk_secure_soc_read()", CURLE_RECV_ERROR); + } + switch(cc) { + case CURLE_OK: + break; + case CURLE_OPERATION_TIMEDOUT: + cc = CURLE_AGAIN; + default: *curlcode = cc; nread = -1; + break; } return (ssize_t) nread; } @@ -555,23 +751,31 @@ static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf, static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; gsk_handle envir; CURLcode result; int rc; - char *keyringfile; - char *keyringpwd; - char *keyringlabel; - char *sni; + const char * const keyringfile = SSL_CONN_CONFIG(CAfile); + const char * const keyringpwd = SSL_SET_OPTION(key_passwd); + const char * const keyringlabel = SSL_SET_OPTION(cert); + const long int ssl_version = SSL_CONN_CONFIG(version); + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); + const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name: + conn->host.name; + const char *sni; unsigned int protoflags; long timeout; Qso_OverlappedIO_t commarea; + int sockpair[2]; + static const int sobufsize = CURL_MAX_WRITE_SIZE; /* Create SSL environment, start (preferably asynchronous) handshake. */ connssl->handle = (gsk_handle) NULL; connssl->iocport = -1; + connssl->localfd = -1; + connssl->remotefd = -1; /* GSKit supports two ways of specifying an SSL context: either by * application identifier (that should have been defined at the system @@ -586,9 +790,6 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) * application identifier mode is tried first, as recommended in IBM doc. */ - keyringfile = data->set.str[STRING_SSL_CAFILE]; - keyringpwd = data->set.str[STRING_KEY_PASSWD]; - keyringlabel = data->set.str[STRING_CERT]; envir = (gsk_handle) NULL; if(keyringlabel && *keyringlabel && !keyringpwd && @@ -613,19 +814,36 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) if(result) return result; + /* Establish a pipelining socket pair for SSL over SSL. */ + if(conn->proxy_ssl[sockindex].use) { + if(inetsocketpair(sockpair)) + return CURLE_SSL_CONNECT_ERROR; + connssl->localfd = sockpair[0]; + connssl->remotefd = sockpair[1]; + setsockopt(connssl->localfd, SOL_SOCKET, SO_RCVBUF, + (void *) sobufsize, sizeof sobufsize); + setsockopt(connssl->remotefd, SOL_SOCKET, SO_RCVBUF, + (void *) sobufsize, sizeof sobufsize); + setsockopt(connssl->localfd, SOL_SOCKET, SO_SNDBUF, + (void *) sobufsize, sizeof sobufsize); + setsockopt(connssl->remotefd, SOL_SOCKET, SO_SNDBUF, + (void *) sobufsize, sizeof sobufsize); + curlx_nonblock(connssl->localfd, TRUE); + curlx_nonblock(connssl->remotefd, TRUE); + } + /* Determine which SSL/TLS version should be enabled. */ - protoflags = CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | - CURL_GSKPROTO_TLSV12_MASK; - sni = conn->host.name; - switch (data->set.ssl.version) { + sni = hostname; + switch(ssl_version) { case CURL_SSLVERSION_SSLv2: protoflags = CURL_GSKPROTO_SSLV2_MASK; - sni = (char *) NULL; + sni = NULL; break; case CURL_SSLVERSION_SSLv3: protoflags = CURL_GSKPROTO_SSLV3_MASK; - sni = (char *) NULL; + sni = NULL; break; + case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: protoflags = CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK; @@ -639,6 +857,12 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) case CURL_SSLVERSION_TLSv1_2: protoflags = CURL_GSKPROTO_TLSV12_MASK; break; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "GSKit: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; } /* Process SNI. Ignore if not supported (on OS400 < V7R1). */ @@ -661,9 +885,12 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) (timeout + 999) / 1000); } if(!result) - result = set_numeric(data, connssl->handle, GSK_FD, conn->sock[sockindex]); + result = set_numeric(data, connssl->handle, GSK_OS400_READ_TIMEOUT, 1); if(!result) - result = set_ciphers(data, connssl->handle, &protoflags); + result = set_numeric(data, connssl->handle, GSK_FD, connssl->localfd >= 0? + connssl->localfd: conn->sock[sockindex]); + if(!result) + result = set_ciphers(conn, connssl->handle, &protoflags); if(!protoflags) { failf(data, "No SSL protocol/cipher combination enabled"); result = CURLE_SSL_CIPHER; @@ -706,7 +933,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) } if(!result) result = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE, - data->set.ssl.verifypeer? GSK_SERVER_AUTH_FULL: + verifypeer? GSK_SERVER_AUTH_FULL: GSK_SERVER_AUTH_PASSTHRU, FALSE); if(!result) { @@ -730,6 +957,10 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) else if(errno != ENOBUFS) result = gskit_status(data, GSK_ERROR_IO, "QsoCreateIOCompletionPort()", 0); + else if(conn->proxy_ssl[sockindex].use) { + /* Cannot pipeline while handshaking synchronously. */ + result = CURLE_SSL_CONNECT_ERROR; + } else { /* No more completion port available. Use synchronous IO. */ result = gskit_status(data, gsk_secure_soc_init(connssl->handle), @@ -742,7 +973,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) } /* Error: rollback. */ - close_one(connssl, data); + close_one(connssl, conn, sockindex); return result; } @@ -750,7 +981,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex) static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex, bool nonblocking) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; Qso_OverlappedIO_t cstat; long timeout_ms; @@ -765,7 +996,7 @@ static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex, timeout_ms = 0; stmv.tv_sec = timeout_ms / 1000; stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000; - switch (QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) { + switch(QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) { case 1: /* Operation complete. */ break; case -1: /* An error occurred: handshake still in progress. */ @@ -801,7 +1032,7 @@ static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex, static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; const gsk_cert_data_elem *cdev; int cdec; @@ -822,7 +1053,7 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) infof(data, "Server certificate:\n"); p = cdev; for(i = 0; i++ < cdec; p++) - switch (p->cert_data_id) { + switch(p->cert_data_id) { case CERT_BODY_DER: cert = p->cert_data_p; certend = cert + cdev->cert_data_l; @@ -865,14 +1096,14 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) } /* Check pinned public key. */ - ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : + data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; if(!result && ptr) { curl_X509certificate x509; curl_asn1Element *p; - if(!cert) + if(Curl_parseX509(&x509, cert, certend)) return CURLE_SSL_PINNEDPUBKEYNOTMATCH; - Curl_parseX509(&x509, cert, certend); p = &x509.subjectPublicKeyInfo; result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header); if(result) { @@ -889,7 +1120,7 @@ static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex) static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex, bool nonblocking, bool *done) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; long timeout_ms; Qso_OverlappedIO_t cstat; @@ -913,6 +1144,11 @@ static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex, result = gskit_connect_step1(conn, sockindex); } + /* Handle handshake pipelining. */ + if(!result) + if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0) + result = CURLE_SSL_CONNECT_ERROR; + /* Step 2: check if handshake is over. */ if(!result && connssl->connecting_state == ssl_connect_2) { /* check allowed time left */ @@ -927,12 +1163,17 @@ static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex, result = gskit_connect_step2(conn, sockindex, nonblocking); } + /* Handle handshake pipelining. */ + if(!result) + if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0) + result = CURLE_SSL_CONNECT_ERROR; + /* Step 3: gather certificate info, verify host. */ if(!result && connssl->connecting_state == ssl_connect_3) result = gskit_connect_step3(conn, sockindex); if(result) - close_one(connssl, data); + close_one(connssl, conn, sockindex); else if(connssl->connecting_state == ssl_connect_done) { connssl->state = ssl_connection_complete; connssl->connecting_state = ssl_connect_1; @@ -976,18 +1217,15 @@ CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex) void Curl_gskit_close(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - if(connssl->use) - close_one(connssl, data); + close_one(&conn->ssl[sockindex], conn, sockindex); + close_one(&conn->proxy_ssl[sockindex], conn, sockindex); } int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; ssize_t nread; int what; int rc; @@ -999,10 +1237,10 @@ int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) return 0; - close_one(connssl, data); + close_one(connssl, conn, sockindex); rc = 0; - what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + what = SOCKET_READABLE(conn->sock[sockindex], + SSL_SHUTDOWN_TIMEOUT); for(;;) { if(what < 0) { @@ -1031,7 +1269,7 @@ int Curl_gskit_shutdown(struct connectdata *conn, int sockindex) if(nread <= 0) break; - what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0); + what = SOCKET_READABLE(conn->sock[sockindex], 0); } return rc; diff --git a/contrib/curl/lib/vtls/gskit.h b/contrib/curl/lib/vtls/gskit.h index 41483cba..22975921 100644 --- a/contrib/curl/lib/vtls/gskit.h +++ b/contrib/curl/lib/vtls/gskit.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -41,6 +41,9 @@ int Curl_gskit_shutdown(struct connectdata *conn, int sockindex); size_t Curl_gskit_version(char *buffer, size_t size); int Curl_gskit_check_cxn(struct connectdata *cxn); +/* Support HTTPS-proxy */ +/* TODO: add '#define HTTPS_PROXY_SUPPORT 1' and fix test #1014 (if need) */ + /* Set the API backend definition to GSKit */ #define CURL_SSL_BACKEND CURLSSLBACKEND_GSKIT @@ -64,7 +67,7 @@ int Curl_gskit_check_cxn(struct connectdata *cxn); #define curlssl_version Curl_gskit_version #define curlssl_check_cxn(x) Curl_gskit_check_cxn(x) #define curlssl_data_pending(x,y) 0 -#define curlssl_random(x,y,z) -1 +#define curlssl_random(x,y,z) (x=x, y=y, z=z, CURLE_NOT_BUILT_IN) #endif /* USE_GSKIT */ diff --git a/contrib/curl/lib/vtls/gtls.c b/contrib/curl/lib/vtls/gtls.c index 1b5a6a4d..faa70aca 100644 --- a/contrib/curl/lib/vtls/gtls.c +++ b/contrib/curl/lib/vtls/gtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -52,7 +52,7 @@ #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" -#include "rawstr.h" +#include "strcase.h" #include "warnless.h" #include "x509asn1.h" #include "curl_printf.h" @@ -68,7 +68,7 @@ #define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p)) #endif #ifndef GNUTLS_INT_TO_POINTER_CAST -#define GNUTLS_INT_TO_POINTER_CAST(i) ((void*) (long) (i)) +#define GNUTLS_INT_TO_POINTER_CAST(i) ((void *) (long) (i)) #endif /* Enable GnuTLS debugging by defining GTLSDEBUG */ @@ -92,11 +92,11 @@ static bool gtls_inited = FALSE; # define GNUTLS_MAPS_WINSOCK_ERRORS 1 # endif -# if (GNUTLS_VERSION_NUMBER >= 0x030200) +# if HAVE_GNUTLS_ALPN_SET_PROTOCOLS # define HAS_ALPN # endif -# if (GNUTLS_VERSION_NUMBER >= 0x03020d) +# if HAVE_GNUTLS_OCSP_REQ_INIT # define HAS_OCSP # endif @@ -171,6 +171,16 @@ static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len) return ret; } +static ssize_t Curl_gtls_push_ssl(void *s, const void *buf, size_t len) +{ + return gnutls_record_send((gnutls_session_t) s, buf, len); +} + +static ssize_t Curl_gtls_pull_ssl(void *s, void *buf, size_t len) +{ + return gnutls_record_recv((gnutls_session_t) s, buf, len); +} + /* Curl_gtls_init() * * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that @@ -201,7 +211,7 @@ int Curl_gtls_cleanup(void) return 1; } -static void showtime(struct SessionHandle *data, +static void showtime(struct Curl_easy *data, const char *text, time_t stamp) { @@ -225,14 +235,15 @@ static void showtime(struct SessionHandle *data, infof(data, "%s\n", data->state.buffer); } -static gnutls_datum_t load_file (const char *file) +static gnutls_datum_t load_file(const char *file) { FILE *f; gnutls_datum_t loaded_file = { NULL, 0 }; long filelen; void *ptr; - if(!(f = fopen(file, "rb"))) + f = fopen(file, "rb"); + if(!f) return loaded_file; if(fseek(f, 0, SEEK_END) != 0 || (filelen = ftell(f)) < 0 @@ -251,7 +262,8 @@ out: return loaded_file; } -static void unload_file(gnutls_datum_t data) { +static void unload_file(gnutls_datum_t data) +{ free(data.data); } @@ -262,7 +274,7 @@ static CURLcode handshake(struct connectdata *conn, bool duringconnect, bool nonblocking) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; gnutls_session_t session = conn->ssl[sockindex].session; curl_socket_t sockfd = conn->sock[sockindex]; @@ -289,7 +301,7 @@ static CURLcode handshake(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, nonblocking?0: timeout_ms?timeout_ms:1000); if(what < 0) { @@ -356,9 +368,9 @@ static gnutls_x509_crt_fmt_t do_file_type(const char *type) { if(!type || !type[0]) return GNUTLS_X509_FMT_PEM; - if(Curl_raw_equal(type, "PEM")) + if(strcasecompare(type, "PEM")) return GNUTLS_X509_FMT_PEM; - if(Curl_raw_equal(type, "DER")) + if(strcasecompare(type, "DER")) return GNUTLS_X509_FMT_DER; return -1; } @@ -367,12 +379,14 @@ static CURLcode gtls_connect_step1(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; + unsigned int init_flags; gnutls_session_t session; int rc; - void *ssl_sessionid; - size_t ssl_idsize; bool sni = TRUE; /* default is SNI enabled */ + void *transport_ptr = NULL; + gnutls_push_func gnutls_transport_push = NULL; + gnutls_pull_func gnutls_transport_pull = NULL; #ifdef ENABLE_IPV6 struct in6_addr addr; #else @@ -399,10 +413,13 @@ gtls_connect_step1(struct connectdata *conn, requested in the priority string, so treat it specially */ #define GNUTLS_SRP "+SRP" - const char* prioritylist; + const char *prioritylist; const char *err = NULL; #endif + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; + if(conn->ssl[sockindex].state == ssl_connection_complete) /* to make us tolerant against being called more than once for the same connection */ @@ -411,12 +428,11 @@ gtls_connect_step1(struct connectdata *conn, if(!gtls_inited) Curl_gtls_init(); - /* GnuTLS only supports SSLv3 and TLSv1 */ - if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { + if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) { failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } - else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) + else if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3) sni = FALSE; /* SSLv3 has no SNI */ /* allocate a cred struct */ @@ -427,8 +443,8 @@ gtls_connect_step1(struct connectdata *conn, } #ifdef USE_TLS_SRP - if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { - infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username); + if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { + infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username)); rc = gnutls_srp_allocate_client_credentials( &conn->ssl[sockindex].srp_client_cred); @@ -440,8 +456,8 @@ gtls_connect_step1(struct connectdata *conn, rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex]. srp_client_cred, - data->set.ssl.username, - data->set.ssl.password); + SSL_SET_OPTION(username), + SSL_SET_OPTION(password)); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_srp_set_client_cred() failed: %s", gnutls_strerror(rc)); @@ -450,68 +466,75 @@ gtls_connect_step1(struct connectdata *conn, } #endif - if(data->set.ssl.CAfile) { + if(SSL_CONN_CONFIG(CAfile)) { /* set the trusted CA cert bundle file */ gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT); rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred, - data->set.ssl.CAfile, + SSL_CONN_CONFIG(CAfile), GNUTLS_X509_FMT_PEM); if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", - data->set.ssl.CAfile, gnutls_strerror(rc)); - if(data->set.ssl.verifypeer) + SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc)); + if(SSL_CONN_CONFIG(verifypeer)) return CURLE_SSL_CACERT_BADFILE; } else - infof(data, "found %d certificates in %s\n", - rc, data->set.ssl.CAfile); + infof(data, "found %d certificates in %s\n", rc, + SSL_CONN_CONFIG(CAfile)); } #ifdef HAS_CAPATH - if(data->set.ssl.CApath) { + if(SSL_CONN_CONFIG(CApath)) { /* set the trusted CA cert directory */ rc = gnutls_certificate_set_x509_trust_dir(conn->ssl[sockindex].cred, - data->set.ssl.CApath, - GNUTLS_X509_FMT_PEM); + SSL_CONN_CONFIG(CApath), + GNUTLS_X509_FMT_PEM); if(rc < 0) { infof(data, "error reading ca cert file %s (%s)\n", - data->set.ssl.CAfile, gnutls_strerror(rc)); - if(data->set.ssl.verifypeer) + SSL_CONN_CONFIG(CApath), gnutls_strerror(rc)); + if(SSL_CONN_CONFIG(verifypeer)) return CURLE_SSL_CACERT_BADFILE; } else infof(data, "found %d certificates in %s\n", - rc, data->set.ssl.CApath); + rc, SSL_CONN_CONFIG(CApath)); } #endif #ifdef CURL_CA_FALLBACK /* use system ca certificate store as fallback */ - if(data->set.ssl.verifypeer && - !(data->set.ssl.CAfile || data->set.ssl.CApath)) { + if(SSL_CONN_CONFIG(verifypeer) && + !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) { gnutls_certificate_set_x509_system_trust(conn->ssl[sockindex].cred); } #endif - if(data->set.ssl.CRLfile) { + if(SSL_SET_OPTION(CRLfile)) { /* set the CRL list file */ rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred, - data->set.ssl.CRLfile, + SSL_SET_OPTION(CRLfile), GNUTLS_X509_FMT_PEM); if(rc < 0) { failf(data, "error reading crl file %s (%s)", - data->set.ssl.CRLfile, gnutls_strerror(rc)); + SSL_SET_OPTION(CRLfile), gnutls_strerror(rc)); return CURLE_SSL_CRL_BADFILE; } else infof(data, "found %d CRL in %s\n", - rc, data->set.ssl.CRLfile); + rc, SSL_SET_OPTION(CRLfile)); } /* Initialize TLS session as a client */ - rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT); + init_flags = GNUTLS_CLIENT; + +#if defined(GNUTLS_NO_TICKETS) + /* Disable TLS session tickets */ + init_flags |= GNUTLS_NO_TICKETS; +#endif + + rc = gnutls_init(&conn->ssl[sockindex].session, init_flags); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_init() failed: %d", rc); return CURLE_SSL_CONNECT_ERROR; @@ -520,13 +543,13 @@ gtls_connect_step1(struct connectdata *conn, /* convenient assign */ session = conn->ssl[sockindex].session; - if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && + if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && #ifdef ENABLE_IPV6 - (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && + (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) && #endif sni && - (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name, - strlen(conn->host.name)) < 0)) + (gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname, + strlen(hostname)) < 0)) infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); @@ -547,13 +570,13 @@ gtls_connect_step1(struct connectdata *conn, if(rc != GNUTLS_E_SUCCESS) return CURLE_SSL_CONNECT_ERROR; - if(data->set.ssl.cipher_list != NULL) { + if(SSL_CONN_CONFIG(cipher_list) != NULL) { failf(data, "can't pass a custom cipher list to older GnuTLS" " versions"); return CURLE_SSL_CONNECT_ERROR; } - switch (data->set.ssl.version) { + switch(SSL_CONN_CONFIG(version) { case CURL_SSLVERSION_SSLv3: protocol_priority[0] = GNUTLS_SSL3; break; @@ -571,12 +594,16 @@ gtls_connect_step1(struct connectdata *conn, break; case CURL_SSLVERSION_TLSv1_2: protocol_priority[0] = GNUTLS_TLS1_2; - break; - case CURL_SSLVERSION_SSLv2: - default: + break; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "GnuTLS: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; + case CURL_SSLVERSION_SSLv2: failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; - break; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; } rc = gnutls_protocol_set_priority(session, protocol_priority); if(rc != GNUTLS_E_SUCCESS) { @@ -588,7 +615,7 @@ gtls_connect_step1(struct connectdata *conn, /* Ensure +SRP comes at the *end* of all relevant strings so that it can be * removed if a run-time error indicates that SRP is not supported by this * GnuTLS version */ - switch (data->set.ssl.version) { + switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_SSLv3: prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0"; sni = false; @@ -609,11 +636,15 @@ gtls_connect_step1(struct connectdata *conn, prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" "+VERS-TLS1.2:" GNUTLS_SRP; break; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "GnuTLS: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; case CURL_SSLVERSION_SSLv2: - default: failf(data, "GnuTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; - break; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; } rc = gnutls_priority_set_direct(session, prioritylist, &err); if((rc == GNUTLS_E_INVALID_REQUEST) && err) { @@ -663,8 +694,8 @@ gtls_connect_step1(struct connectdata *conn, } #endif - if(data->set.str[STRING_CERT]) { - if(data->set.str[STRING_KEY_PASSWD]) { + if(SSL_SET_OPTION(cert)) { + if(SSL_SET_OPTION(key_passwd)) { #if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2 const unsigned int supported_key_encryption_algorithms = GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR | @@ -673,11 +704,11 @@ gtls_connect_step1(struct connectdata *conn, GNUTLS_PKCS_USE_PBES2_AES_256; rc = gnutls_certificate_set_x509_key_file2( conn->ssl[sockindex].cred, - data->set.str[STRING_CERT], - data->set.str[STRING_KEY] ? - data->set.str[STRING_KEY] : data->set.str[STRING_CERT], - do_file_type(data->set.str[STRING_CERT_TYPE]), - data->set.str[STRING_KEY_PASSWD], + SSL_SET_OPTION(cert), + SSL_SET_OPTION(key) ? + SSL_SET_OPTION(key) : SSL_SET_OPTION(cert), + do_file_type(SSL_SET_OPTION(cert_type)), + SSL_SET_OPTION(key_passwd), supported_key_encryption_algorithms); if(rc != GNUTLS_E_SUCCESS) { failf(data, @@ -691,15 +722,14 @@ gtls_connect_step1(struct connectdata *conn, #endif } else { - rc = gnutls_certificate_set_x509_key_file( + if(gnutls_certificate_set_x509_key_file( conn->ssl[sockindex].cred, - data->set.str[STRING_CERT], - data->set.str[STRING_KEY] ? - data->set.str[STRING_KEY] : data->set.str[STRING_CERT], - do_file_type(data->set.str[STRING_CERT_TYPE]) ); - if(rc != GNUTLS_E_SUCCESS) { - failf(data, "error reading X.509 key or certificate file: %s", - gnutls_strerror(rc)); + SSL_SET_OPTION(cert), + SSL_SET_OPTION(key) ? + SSL_SET_OPTION(key) : SSL_SET_OPTION(cert), + do_file_type(SSL_SET_OPTION(cert_type)) ) != + GNUTLS_E_SUCCESS) { + failf(data, "error reading X.509 key or certificate file"); return CURLE_SSL_CONNECT_ERROR; } } @@ -707,7 +737,7 @@ gtls_connect_step1(struct connectdata *conn, #ifdef USE_TLS_SRP /* put the credentials to the current session */ - if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { + if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) { rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP, conn->ssl[sockindex].srp_client_cred); if(rc != GNUTLS_E_SUCCESS) { @@ -726,19 +756,30 @@ gtls_connect_step1(struct connectdata *conn, } } - /* set the connection handle (file descriptor for the socket) */ - gnutls_transport_set_ptr(session, - GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex])); + if(conn->proxy_ssl[sockindex].use) { + transport_ptr = conn->proxy_ssl[sockindex].session; + gnutls_transport_push = Curl_gtls_push_ssl; + gnutls_transport_pull = Curl_gtls_pull_ssl; + } + else { + /* file descriptor for the socket */ + transport_ptr = GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex]); + gnutls_transport_push = Curl_gtls_push; + gnutls_transport_pull = Curl_gtls_pull; + } + + /* set the connection handle */ + gnutls_transport_set_ptr(session, transport_ptr); /* register callback functions to send and receive data. */ - gnutls_transport_set_push_function(session, Curl_gtls_push); - gnutls_transport_set_pull_function(session, Curl_gtls_pull); + gnutls_transport_set_push_function(session, gnutls_transport_push); + gnutls_transport_set_pull_function(session, gnutls_transport_pull); /* lowat must be set to zero when using custom push and pull functions. */ gnutls_transport_set_lowat(session, 0); #ifdef HAS_OCSP - if(data->set.ssl.verifystatus) { + if(SSL_CONN_CONFIG(verifystatus)) { rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL); if(rc != GNUTLS_E_SUCCESS) { failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc); @@ -749,19 +790,25 @@ gtls_connect_step1(struct connectdata *conn, /* This might be a reconnect, so we check for a session ID in the cache to speed up things */ + if(data->set.general_ssl.sessionid) { + void *ssl_sessionid; + size_t ssl_idsize; - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) { - /* we got a session id, use it! */ - gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize, sockindex)) { + /* we got a session id, use it! */ + gnutls_session_set_data(session, ssl_sessionid, ssl_idsize); - /* Informational message */ - infof (data, "SSL re-using session ID\n"); + /* Informational message */ + infof(data, "SSL re-using session ID\n"); + } + Curl_ssl_sessionid_unlock(conn); } return CURLE_OK; } -static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data, +static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, gnutls_x509_crt_t cert, const char *pinnedpubkey) { @@ -836,17 +883,16 @@ gtls_connect_step3(struct connectdata *conn, unsigned int bits; time_t certclock; const char *ptr; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; gnutls_session_t session = conn->ssl[sockindex].session; int rc; - bool incache; - void *ssl_sessionid; #ifdef HAS_ALPN gnutls_datum_t proto; #endif CURLcode result = CURLE_OK; - gnutls_protocol_t version = gnutls_protocol_get_version(session); + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */ ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session), @@ -864,13 +910,13 @@ gtls_connect_step3(struct connectdata *conn, chainp = gnutls_certificate_get_peers(session, &cert_list_size); if(!chainp) { - if(data->set.ssl.verifypeer || - data->set.ssl.verifyhost || - data->set.ssl.issuercert) { + if(SSL_CONN_CONFIG(verifypeer) || + SSL_CONN_CONFIG(verifyhost) || + SSL_SET_OPTION(issuercert)) { #ifdef USE_TLS_SRP - if(data->set.ssl.authtype == CURL_TLSAUTH_SRP - && data->set.ssl.username != NULL - && !data->set.ssl.verifypeer + if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP + && SSL_SET_OPTION(username) != NULL + && !SSL_CONN_CONFIG(verifypeer) && gnutls_cipher_get(session)) { /* no peer cert, but auth is ok if we have SRP user and cipher and no peer verify */ @@ -903,7 +949,7 @@ gtls_connect_step3(struct connectdata *conn, } } - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { /* This function will try to verify the peer's certificate and return its status (trusted, invalid etc.). The value of status should be one or more of the gnutls_certificate_status_t enumerated elements bitwise @@ -919,10 +965,11 @@ gtls_connect_step3(struct connectdata *conn, /* verify_status is a bitmask of gnutls_certificate_status bits */ if(verify_status & GNUTLS_CERT_INVALID) { - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server certificate verification failed. CAfile: %s " - "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none", - data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none"); + "CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile): + "none", + SSL_SET_OPTION(CRLfile)?SSL_SET_OPTION(CRLfile):"none"); return CURLE_SSL_CACERT; } else @@ -935,7 +982,7 @@ gtls_connect_step3(struct connectdata *conn, infof(data, "\t server certificate verification SKIPPED\n"); #ifdef HAS_OCSP - if(data->set.ssl.verifystatus) { + if(SSL_CONN_CONFIG(verifystatus)) { if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) { gnutls_datum_t status_request; gnutls_ocsp_resp_t ocsp_resp; @@ -1047,21 +1094,21 @@ gtls_connect_step3(struct connectdata *conn, gnutls_x509_crt_t format */ gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); - if(data->set.ssl.issuercert) { + if(SSL_SET_OPTION(issuercert)) { gnutls_x509_crt_init(&x509_issuer); - issuerp = load_file(data->set.ssl.issuercert); + issuerp = load_file(SSL_SET_OPTION(issuercert)); gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer); gnutls_x509_crt_deinit(x509_issuer); unload_file(issuerp); if(rc <= 0) { failf(data, "server certificate issuer check failed (IssuerCert: %s)", - data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); + SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_ISSUER_ERROR; } infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n", - data->set.ssl.issuercert?data->set.ssl.issuercert:"none"); + SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none"); } size=sizeof(certbuf); @@ -1080,7 +1127,7 @@ gtls_connect_step3(struct connectdata *conn, in RFC2818 (HTTPS), which takes into account wildcards, and the subject alternative name PKIX extension. Returns non zero on success, and zero on failure. */ - rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name); + rc = gnutls_x509_crt_check_hostname(x509_cert, hostname); #if GNUTLS_VERSION_NUMBER < 0x030306 /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP addresses. */ @@ -1096,10 +1143,10 @@ gtls_connect_step3(struct connectdata *conn, int i; int ret = 0; - if(Curl_inet_pton(AF_INET, conn->host.name, addrbuf) > 0) + if(Curl_inet_pton(AF_INET, hostname, addrbuf) > 0) addrlen = 4; #ifdef ENABLE_IPV6 - else if(Curl_inet_pton(AF_INET6, conn->host.name, addrbuf) > 0) + else if(Curl_inet_pton(AF_INET6, hostname, addrbuf) > 0) addrlen = 16; #endif @@ -1124,15 +1171,18 @@ gtls_connect_step3(struct connectdata *conn, } #endif if(!rc) { - if(data->set.ssl.verifyhost) { + const char * const dispname = SSL_IS_PROXY() ? + conn->http_proxy.host.dispname : conn->host.dispname; + + if(SSL_CONN_CONFIG(verifyhost)) { failf(data, "SSL: certificate subject name (%s) does not match " - "target host name '%s'", certbuf, conn->host.dispname); + "target host name '%s'", certbuf, dispname); gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; } else infof(data, "\t common name: %s (does not match '%s')\n", - certbuf, conn->host.dispname); + certbuf, dispname); } else infof(data, "\t common name: %s (matched)\n", certbuf); @@ -1141,7 +1191,7 @@ gtls_connect_step3(struct connectdata *conn, certclock = gnutls_x509_crt_get_expiration_time(x509_cert); if(certclock == (time_t)-1) { - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server cert expiration date verify failed"); gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_CONNECT_ERROR; @@ -1151,7 +1201,7 @@ gtls_connect_step3(struct connectdata *conn, } else { if(certclock < time(NULL)) { - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server certificate expiration date has passed."); gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; @@ -1166,7 +1216,7 @@ gtls_connect_step3(struct connectdata *conn, certclock = gnutls_x509_crt_get_activation_time(x509_cert); if(certclock == (time_t)-1) { - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server cert activation date verify failed"); gnutls_x509_crt_deinit(x509_cert); return CURLE_SSL_CONNECT_ERROR; @@ -1176,7 +1226,7 @@ gtls_connect_step3(struct connectdata *conn, } else { if(certclock > time(NULL)) { - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { failf(data, "server certificate not activated yet."); gnutls_x509_crt_deinit(x509_cert); return CURLE_PEER_FAILED_VERIFICATION; @@ -1188,7 +1238,8 @@ gtls_connect_step3(struct connectdata *conn, infof(data, "\t server certificate activation date OK\n"); } - ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : + data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; if(ptr) { result = pkp_pin_peer_pubkey(data, x509_cert, ptr); if(result != CURLE_OK) { @@ -1268,11 +1319,13 @@ gtls_connect_step3(struct connectdata *conn, conn->recv[sockindex] = gtls_recv; conn->send[sockindex] = gtls_send; - { + if(data->set.general_ssl.sessionid) { /* we always unconditionally get the session id here, as even if we already got it from the cache and asked to use it in the connection, it might've been rejected and then a new one is in use now and we need to detect that. */ + bool incache; + void *ssl_sessionid; void *connect_sessionid; size_t connect_idsize = 0; @@ -1284,7 +1337,9 @@ gtls_connect_step3(struct connectdata *conn, /* extract session ID to the allocated buffer */ gnutls_session_get_data(session, connect_sessionid, &connect_idsize); - incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)); + Curl_ssl_sessionid_lock(conn); + incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, + sockindex)); if(incache) { /* there was one before in the cache, so instead of risking that the previous one was rejected, we just kill that and store the new */ @@ -1292,7 +1347,9 @@ gtls_connect_step3(struct connectdata *conn, } /* store this session id */ - result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize); + result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize, + sockindex); + Curl_ssl_sessionid_unlock(conn); if(result) { free(connect_sessionid); result = CURLE_OUT_OF_MEMORY; @@ -1326,7 +1383,7 @@ gtls_connect_common(struct connectdata *conn, /* Initiate the connection, if not already done */ if(ssl_connect_1==connssl->connecting_state) { - rc = gtls_connect_step1 (conn, sockindex); + rc = gtls_connect_step1(conn, sockindex); if(rc) return rc; } @@ -1373,6 +1430,20 @@ Curl_gtls_connect(struct connectdata *conn, return CURLE_OK; } +bool Curl_gtls_data_pending(const struct connectdata *conn, int connindex) +{ + bool res = FALSE; + if(conn->ssl[connindex].session && + 0 != gnutls_record_check_pending(conn->ssl[connindex].session)) + res = TRUE; + + if(conn->proxy_ssl[connindex].session && + 0 != gnutls_record_check_pending(conn->proxy_ssl[connindex].session)) + res = TRUE; + + return res; +} + static ssize_t gtls_send(struct connectdata *conn, int sockindex, const void *mem, @@ -1392,29 +1463,29 @@ static ssize_t gtls_send(struct connectdata *conn, return rc; } -static void close_one(struct connectdata *conn, - int idx) +static void close_one(struct ssl_connect_data *ssl) { - if(conn->ssl[idx].session) { - gnutls_bye(conn->ssl[idx].session, GNUTLS_SHUT_RDWR); - gnutls_deinit(conn->ssl[idx].session); - conn->ssl[idx].session = NULL; + if(ssl->session) { + gnutls_bye(ssl->session, GNUTLS_SHUT_RDWR); + gnutls_deinit(ssl->session); + ssl->session = NULL; } - if(conn->ssl[idx].cred) { - gnutls_certificate_free_credentials(conn->ssl[idx].cred); - conn->ssl[idx].cred = NULL; + if(ssl->cred) { + gnutls_certificate_free_credentials(ssl->cred); + ssl->cred = NULL; } #ifdef USE_TLS_SRP - if(conn->ssl[idx].srp_client_cred) { - gnutls_srp_free_client_credentials(conn->ssl[idx].srp_client_cred); - conn->ssl[idx].srp_client_cred = NULL; + if(ssl->srp_client_cred) { + gnutls_srp_free_client_credentials(ssl->srp_client_cred); + ssl->srp_client_cred = NULL; } #endif } void Curl_gtls_close(struct connectdata *conn, int sockindex) { - close_one(conn, sockindex); + close_one(&conn->ssl[sockindex]); + close_one(&conn->proxy_ssl[sockindex]); } /* @@ -1425,7 +1496,7 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) { ssize_t result; int retval = 0; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int done = 0; char buf[120]; @@ -1439,8 +1510,8 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) if(conn->ssl[sockindex].session) { while(!done) { - int what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + int what = SOCKET_READABLE(conn->sock[sockindex], + SSL_SHUTDOWN_TIMEOUT); if(what > 0) { /* Something to read, let's do it and hope that it is the close notify alert from the server */ @@ -1480,8 +1551,8 @@ int Curl_gtls_shutdown(struct connectdata *conn, int sockindex) gnutls_certificate_free_credentials(conn->ssl[sockindex].cred); #ifdef USE_TLS_SRP - if(data->set.ssl.authtype == CURL_TLSAUTH_SRP - && data->set.ssl.username != NULL) + if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP + && SSL_SET_OPTION(username) != NULL) gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred); #endif @@ -1538,7 +1609,7 @@ size_t Curl_gtls_version(char *buffer, size_t size) } #ifndef USE_GNUTLS_NETTLE -static int Curl_gtls_seed(struct SessionHandle *data) +static int Curl_gtls_seed(struct Curl_easy *data) { /* we have the "SSL is seeded" boolean static to prevent multiple time-consuming seedings in vain */ @@ -1562,19 +1633,21 @@ static int Curl_gtls_seed(struct SessionHandle *data) #endif /* data might be NULL! */ -int Curl_gtls_random(struct SessionHandle *data, - unsigned char *entropy, - size_t length) +CURLcode Curl_gtls_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length) { #if defined(USE_GNUTLS_NETTLE) + int rc; (void)data; - gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length); + rc = gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length); + return rc?CURLE_FAILED_INIT:CURLE_OK; #elif defined(USE_GNUTLS) if(data) Curl_gtls_seed(data); /* Initiate the seed if not already done */ gcry_randomize(entropy, length, GCRY_STRONG_RANDOM); #endif - return 0; + return CURLE_OK; } void Curl_gtls_md5sum(unsigned char *tmp, /* input */ @@ -1591,7 +1664,7 @@ void Curl_gtls_md5sum(unsigned char *tmp, /* input */ gcry_md_hd_t MD5pw; gcry_md_open(&MD5pw, GCRY_MD_MD5, 0); gcry_md_write(MD5pw, tmp, tmplen); - memcpy(md5sum, gcry_md_read (MD5pw, 0), md5len); + memcpy(md5sum, gcry_md_read(MD5pw, 0), md5len); gcry_md_close(MD5pw); #endif } @@ -1610,7 +1683,7 @@ void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */ gcry_md_hd_t SHA256pw; gcry_md_open(&SHA256pw, GCRY_MD_SHA256, 0); gcry_md_write(SHA256pw, tmp, tmplen); - memcpy(sha256sum, gcry_md_read (SHA256pw, 0), sha256len); + memcpy(sha256sum, gcry_md_read(SHA256pw, 0), sha256len); gcry_md_close(SHA256pw); #endif } diff --git a/contrib/curl/lib/vtls/gtls.h b/contrib/curl/lib/vtls/gtls.h index 611a2f47..462c0485 100644 --- a/contrib/curl/lib/vtls/gtls.h +++ b/contrib/curl/lib/vtls/gtls.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -34,6 +34,8 @@ CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex); CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done); +bool Curl_gtls_data_pending(const struct connectdata *conn, + int connindex); /* close a SSL connection */ void Curl_gtls_close(struct connectdata *conn, int sockindex); @@ -41,9 +43,9 @@ void Curl_gtls_close(struct connectdata *conn, int sockindex); void Curl_gtls_session_free(void *ptr); size_t Curl_gtls_version(char *buffer, size_t size); int Curl_gtls_shutdown(struct connectdata *conn, int sockindex); -int Curl_gtls_random(struct SessionHandle *data, - unsigned char *entropy, - size_t length); +CURLcode Curl_gtls_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length); void Curl_gtls_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum, /* output */ @@ -55,6 +57,9 @@ void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */ bool Curl_gtls_cert_status_request(void); +/* Support HTTPS-proxy */ +#define HTTPS_PROXY_SUPPORT 1 + /* Set the API backend definition to GnuTLS */ #define CURL_SSL_BACKEND CURLSSLBACKEND_GNUTLS @@ -81,7 +86,7 @@ bool Curl_gtls_cert_status_request(void); #define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) #define curlssl_version Curl_gtls_version #define curlssl_check_cxn(x) ((void)x, -1) -#define curlssl_data_pending(x,y) ((void)x, (void)y, 0) +#define curlssl_data_pending(x,y) Curl_gtls_data_pending(x,y) #define curlssl_random(x,y,z) Curl_gtls_random(x,y,z) #define curlssl_md5sum(a,b,c,d) Curl_gtls_md5sum(a,b,c,d) #define curlssl_sha256sum(a,b,c,d) Curl_gtls_sha256sum(a,b,c,d) diff --git a/contrib/curl/lib/vtls/mbedtls.c b/contrib/curl/lib/vtls/mbedtls.c index ef0b9492..07239bf2 100644 --- a/contrib/curl/lib/vtls/mbedtls.c +++ b/contrib/curl/lib/vtls/mbedtls.c @@ -6,7 +6,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2010 - 2011, Hoi-Ho Chan, - * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -31,11 +31,15 @@ #ifdef USE_MBEDTLS +#include +#if MBEDTLS_VERSION_NUMBER >= 0x02040000 +#include +#else #include +#endif #include #include #include -#include #include #include @@ -50,7 +54,6 @@ #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" -#include "rawstr.h" #include "polarssl_threadlock.h" /* The last 3 #include files should be in this order */ @@ -103,12 +106,12 @@ static int entropy_func_mutex(void *data, unsigned char *output, size_t len) static void mbed_debug(void *context, int level, const char *f_name, int line_nb, const char *line) { - struct SessionHandle *data = NULL; + struct Curl_easy *data = NULL; if(!context) return; - data = (struct SessionHandle *)context; + data = (struct Curl_easy *)context; infof(data, "%s", line); (void) level; @@ -158,27 +161,25 @@ static CURLcode mbed_connect_step1(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; - - bool sni = TRUE; /* default is SNI enabled */ + const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); + const char * const ssl_capath = SSL_CONN_CONFIG(CApath); + char * const ssl_cert = SSL_SET_OPTION(cert); + const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; + const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; int ret = -1; -#ifdef ENABLE_IPV6 - struct in6_addr addr; -#else - struct in_addr addr; -#endif - void *old_session = NULL; char errorbuf[128]; errorbuf[0]=0; /* mbedTLS only supports SSLv3 and TLSv1 */ - if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { + if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) { failf(data, "mbedTLS does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } - else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) - sni = FALSE; /* SSLv3 has no SNI */ #ifdef THREADING_SUPPORT entropy_init_mutex(&entropy); @@ -211,34 +212,32 @@ mbed_connect_step1(struct connectdata *conn, /* Load the trusted CA */ mbedtls_x509_crt_init(&connssl->cacert); - if(data->set.str[STRING_SSL_CAFILE]) { - ret = mbedtls_x509_crt_parse_file(&connssl->cacert, - data->set.str[STRING_SSL_CAFILE]); + if(ssl_cafile) { + ret = mbedtls_x509_crt_parse_file(&connssl->cacert, ssl_cafile); if(ret<0) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s", - data->set.str[STRING_SSL_CAFILE], -ret, errorbuf); + ssl_cafile, -ret, errorbuf); - if(data->set.ssl.verifypeer) + if(verifypeer) return CURLE_SSL_CACERT_BADFILE; } } - if(data->set.str[STRING_SSL_CAPATH]) { - ret = mbedtls_x509_crt_parse_path(&connssl->cacert, - data->set.str[STRING_SSL_CAPATH]); + if(ssl_capath) { + ret = mbedtls_x509_crt_parse_path(&connssl->cacert, ssl_capath); if(ret<0) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s", - data->set.str[STRING_SSL_CAPATH], -ret, errorbuf); + ssl_capath, -ret, errorbuf); - if(data->set.ssl.verifypeer) + if(verifypeer) return CURLE_SSL_CACERT_BADFILE; } } @@ -246,16 +245,15 @@ mbed_connect_step1(struct connectdata *conn, /* Load the client certificate */ mbedtls_x509_crt_init(&connssl->clicert); - if(data->set.str[STRING_CERT]) { - ret = mbedtls_x509_crt_parse_file(&connssl->clicert, - data->set.str[STRING_CERT]); + if(ssl_cert) { + ret = mbedtls_x509_crt_parse_file(&connssl->clicert, ssl_cert); if(ret) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s", - data->set.str[STRING_CERT], -ret, errorbuf); + ssl_cert, -ret, errorbuf); return CURLE_SSL_CERTPROBLEM; } @@ -264,9 +262,9 @@ mbed_connect_step1(struct connectdata *conn, /* Load the client private key */ mbedtls_pk_init(&connssl->pk); - if(data->set.str[STRING_KEY]) { - ret = mbedtls_pk_parse_keyfile(&connssl->pk, data->set.str[STRING_KEY], - data->set.str[STRING_KEY_PASSWD]); + if(SSL_SET_OPTION(key)) { + ret = mbedtls_pk_parse_keyfile(&connssl->pk, SSL_SET_OPTION(key), + SSL_SET_OPTION(key_passwd)); if(ret == 0 && !mbedtls_pk_can_do(&connssl->pk, MBEDTLS_PK_RSA)) ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; @@ -275,7 +273,7 @@ mbed_connect_step1(struct connectdata *conn, mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s", - data->set.str[STRING_KEY], -ret, errorbuf); + SSL_SET_OPTION(key), -ret, errorbuf); return CURLE_SSL_CERTPROBLEM; } @@ -284,23 +282,21 @@ mbed_connect_step1(struct connectdata *conn, /* Load the CRL */ mbedtls_x509_crl_init(&connssl->crl); - if(data->set.str[STRING_SSL_CRLFILE]) { - ret = mbedtls_x509_crl_parse_file(&connssl->crl, - data->set.str[STRING_SSL_CRLFILE]); + if(ssl_crlfile) { + ret = mbedtls_x509_crl_parse_file(&connssl->crl, ssl_crlfile); if(ret) { #ifdef MBEDTLS_ERROR_C mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); #endif /* MBEDTLS_ERROR_C */ failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s", - data->set.str[STRING_SSL_CRLFILE], -ret, errorbuf); + ssl_crlfile, -ret, errorbuf); return CURLE_SSL_CRL_BADFILE; } } - infof(data, "mbedTLS: Connecting to %s:%d\n", - conn->host.name, conn->remote_port); + infof(data, "mbedTLS: Connecting to %s:%d\n", hostname, port); mbedtls_ssl_config_init(&connssl->config); @@ -322,7 +318,7 @@ mbed_connect_step1(struct connectdata *conn, mbedtls_ssl_conf_cert_profile(&connssl->config, &mbedtls_x509_crt_profile_fr); - switch(data->set.ssl.version) { + switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3, @@ -357,8 +353,11 @@ mbed_connect_step1(struct connectdata *conn, MBEDTLS_SSL_MINOR_VERSION_3); infof(data, "mbedTLS: Set SSL version to TLS 1.2\n"); break; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "mbedTLS: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; default: - failf(data, "mbedTLS: Unsupported SSL protocol version"); + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } @@ -373,24 +372,38 @@ mbed_connect_step1(struct connectdata *conn, mbedtls_ssl_conf_ciphersuites(&connssl->config, mbedtls_ssl_list_ciphersuites()); - if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) { - ret = mbedtls_ssl_set_session(&connssl->ssl, old_session); - if(ret) { - failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret); - return CURLE_SSL_CONNECT_ERROR; + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + mbedtls_ssl_conf_session_tickets(&connssl->config, + MBEDTLS_SSL_SESSION_TICKETS_DISABLED); +#endif + + /* Check if there's a cached ID we can/should use here! */ + if(data->set.general_ssl.sessionid) { + void *old_session = NULL; + + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) { + ret = mbedtls_ssl_set_session(&connssl->ssl, old_session); + if(ret) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret); + return CURLE_SSL_CONNECT_ERROR; + } + infof(data, "mbedTLS re-using session\n"); } - infof(data, "mbedTLS re-using session\n"); + Curl_ssl_sessionid_unlock(conn); } mbedtls_ssl_conf_ca_chain(&connssl->config, &connssl->cacert, &connssl->crl); - if(data->set.str[STRING_KEY]) { + if(SSL_SET_OPTION(key)) { mbedtls_ssl_conf_own_cert(&connssl->config, &connssl->clicert, &connssl->pk); } - if(mbedtls_ssl_set_hostname(&connssl->ssl, conn->host.name)) { + if(mbedtls_ssl_set_hostname(&connssl->ssl, hostname)) { /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks *and* the name to set in the SNI extension. So even if curl connects to a host specified as an IP address, this function must be used. */ @@ -420,7 +433,15 @@ mbed_connect_step1(struct connectdata *conn, #endif #ifdef MBEDTLS_DEBUG - mbedtls_ssl_conf_dbg(&connssl->config, mbedtls_debug, data); + /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */ + mbedtls_ssl_conf_dbg(&connssl->config, mbed_debug, data); + /* - 0 No debug + * - 1 Error + * - 2 State change + * - 3 Informational + * - 4 Verbose + */ + mbedtls_debug_set_threshold(4); #endif connssl->connecting_state = ssl_connect_2; @@ -433,12 +454,15 @@ mbed_connect_step2(struct connectdata *conn, int sockindex) { int ret; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; const mbedtls_x509_crt *peercert; + const char * const pinnedpubkey = SSL_IS_PROXY() ? + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : + data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; #ifdef HAS_ALPN - const char* next_protocol; + const char *next_protocol; #endif char errorbuf[128]; @@ -472,7 +496,7 @@ mbed_connect_step2(struct connectdata *conn, ret = mbedtls_ssl_get_verify_result(&conn->ssl[sockindex].ssl); - if(ret && data->set.ssl.verifypeer) { + if(ret && SSL_CONN_CONFIG(verifypeer)) { if(ret & MBEDTLS_X509_BADCERT_EXPIRED) failf(data, "Cert verify failed: BADCERT_EXPIRED"); @@ -507,7 +531,7 @@ mbed_connect_step2(struct connectdata *conn, free(buffer); } - if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { + if(pinnedpubkey) { int size; CURLcode result; mbedtls_x509_crt *p; @@ -546,7 +570,7 @@ mbed_connect_step2(struct connectdata *conn, /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */ result = Curl_pin_peer_pubkey(data, - data->set.str[STRING_SSL_PINNEDPUBLICKEY], + pinnedpubkey, &pubkey[PUB_DER_MAX_BYTES - size], size); if(result) { mbedtls_x509_crt_free(p); @@ -595,34 +619,39 @@ mbed_connect_step3(struct connectdata *conn, { CURLcode retcode = CURLE_OK; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; - void *old_ssl_sessionid = NULL; - mbedtls_ssl_session *our_ssl_sessionid; - int ret; + struct Curl_easy *data = conn->data; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session)); - if(!our_ssl_sessionid) - return CURLE_OUT_OF_MEMORY; + if(data->set.general_ssl.sessionid) { + int ret; + mbedtls_ssl_session *our_ssl_sessionid; + void *old_ssl_sessionid = NULL; - mbedtls_ssl_session_init(our_ssl_sessionid); + our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session)); + if(!our_ssl_sessionid) + return CURLE_OUT_OF_MEMORY; - ret = mbedtls_ssl_get_session(&connssl->ssl, our_ssl_sessionid); - if(ret) { - failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret); - return CURLE_SSL_CONNECT_ERROR; - } + mbedtls_ssl_session_init(our_ssl_sessionid); - /* If there's already a matching session in the cache, delete it */ - if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)) - Curl_ssl_delsessionid(conn, old_ssl_sessionid); + ret = mbedtls_ssl_get_session(&connssl->ssl, our_ssl_sessionid); + if(ret) { + failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret); + return CURLE_SSL_CONNECT_ERROR; + } - retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0); - if(retcode) { - free(our_ssl_sessionid); - failf(data, "failed to store ssl session"); - return retcode; + /* If there's already a matching session in the cache, delete it */ + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex)) + Curl_ssl_delsessionid(conn, old_ssl_sessionid); + + retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex); + Curl_ssl_sessionid_unlock(conn); + if(retcode) { + free(our_ssl_sessionid); + failf(data, "failed to store ssl session"); + return retcode; + } } connssl->connecting_state = ssl_connect_done; @@ -648,7 +677,7 @@ static ssize_t mbed_send(struct connectdata *conn, int sockindex, return ret; } -void Curl_mbedtls_close_all(struct SessionHandle *data) +void Curl_mbedtls_close_all(struct Curl_easy *data) { (void)data; } @@ -705,6 +734,55 @@ size_t Curl_mbedtls_version(char *buffer, size_t size) (version>>16)&0xff, (version>>8)&0xff); } +CURLcode Curl_mbedtls_random(struct Curl_easy *data, unsigned char *entropy, + size_t length) +{ +#if defined(MBEDTLS_CTR_DRBG_C) + int ret = -1; + char errorbuf[128]; + mbedtls_entropy_context ctr_entropy; + mbedtls_ctr_drbg_context ctr_drbg; + mbedtls_entropy_init(&ctr_entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + errorbuf[0]=0; + + ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, + &ctr_entropy, NULL, 0); + + if(ret) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "Failed - mbedTLS: ctr_drbg_seed returned (-0x%04X) %s\n", + -ret, errorbuf); + } + else { + ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length); + + if(ret) { +#ifdef MBEDTLS_ERROR_C + mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); +#endif /* MBEDTLS_ERROR_C */ + failf(data, "mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n", + -ret, errorbuf); + } + } + + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&ctr_entropy); + + return ret == 0 ? CURLE_OK : CURLE_FAILED_INIT; +#elif defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_state hs; + mbedtls_havege_init(&hs); + mbedtls_havege_random(&hs, entropy, length); + mbedtls_havege_free(&hs); + return CURLE_OK; +#else + return CURLE_NOT_BUILT_IN; +#endif +} + static CURLcode mbed_connect_common(struct connectdata *conn, int sockindex, @@ -712,7 +790,7 @@ mbed_connect_common(struct connectdata *conn, bool *done) { CURLcode retcode; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; long timeout_ms; @@ -760,7 +838,8 @@ mbed_connect_common(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking ? 0 : timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -858,9 +937,7 @@ void Curl_mbedtls_cleanup(void) int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex) { - mbedtls_ssl_context *ssl = - (mbedtls_ssl_context *)&conn->ssl[sockindex].ssl; - return ssl->in_msglen != 0; + return mbedtls_ssl_get_bytes_avail(&conn->ssl[sockindex].ssl) != 0; } #endif /* USE_MBEDTLS */ diff --git a/contrib/curl/lib/vtls/mbedtls.h b/contrib/curl/lib/vtls/mbedtls.h index 9117fff1..5b0bcf6d 100644 --- a/contrib/curl/lib/vtls/mbedtls.h +++ b/contrib/curl/lib/vtls/mbedtls.h @@ -41,7 +41,7 @@ CURLcode Curl_mbedtls_connect_nonblocking(struct connectdata *conn, /* tell mbedTLS to close down all open information regarding connections (and thus session ID caching etc) */ -void Curl_mbedtls_close_all(struct SessionHandle *data); +void Curl_mbedtls_close_all(struct Curl_easy *data); /* close a SSL connection */ void Curl_mbedtls_close(struct connectdata *conn, int sockindex); @@ -50,6 +50,9 @@ void Curl_mbedtls_session_free(void *ptr); size_t Curl_mbedtls_version(char *buffer, size_t size); int Curl_mbedtls_shutdown(struct connectdata *conn, int sockindex); +CURLcode Curl_mbedtls_random(struct Curl_easy *data, unsigned char *entropy, + size_t length); + /* this backends supports CURLOPT_PINNEDPUBLICKEY */ #define have_curlssl_pinnedpubkey 1 @@ -70,11 +73,7 @@ int Curl_mbedtls_shutdown(struct connectdata *conn, int sockindex); #define curlssl_data_pending(x,y) Curl_mbedtls_data_pending(x, y) #define CURL_SSL_BACKEND CURLSSLBACKEND_MBEDTLS #define curlssl_sha256sum(a,b,c,d) mbedtls_sha256(a,b,c,0) - -/* This might cause libcurl to use a weeker random! - TODO: implement proper use of Polarssl's CTR-DRBG or HMAC-DRBG and use that -*/ -#define curlssl_random(x,y,z) (x=x, y=y, z=z, CURLE_NOT_BUILT_IN) +#define curlssl_random(x,y,z) Curl_mbedtls_random(x, y, z) #endif /* USE_MBEDTLS */ #endif /* HEADER_CURL_MBEDTLS_H */ diff --git a/contrib/curl/lib/vtls/nss.c b/contrib/curl/lib/vtls/nss.c index 02c8727e..d5158ace 100644 --- a/contrib/curl/lib/vtls/nss.c +++ b/contrib/curl/lib/vtls/nss.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -34,7 +34,7 @@ #include "formdata.h" /* for the boundary function */ #include "url.h" /* for the ssl config check function */ #include "connect.h" -#include "strequal.h" +#include "strcase.h" #include "select.h" #include "vtls.h" #include "llist.h" @@ -64,7 +64,7 @@ #include #endif -#include "rawstr.h" +#include "strcase.h" #include "warnless.h" #include "x509asn1.h" @@ -78,13 +78,12 @@ #define SLOTSIZE 13 PRFileDesc *PR_ImportTCPSocket(PRInt32 osfd); - -PRLock * nss_initlock = NULL; -PRLock * nss_crllock = NULL; -struct curl_llist *nss_crl_list = NULL; -NSSInitContext * nss_context = NULL; - -volatile int initialized = 0; +static PRLock *nss_initlock = NULL; +static PRLock *nss_crllock = NULL; +static PRLock *nss_findslot_lock = NULL; +static struct curl_llist *nss_crl_list = NULL; +static NSSInitContext *nss_context = NULL; +static volatile int initialized = 0; typedef struct { const char *name; @@ -150,7 +149,7 @@ static const cipher_s cipherlist[] = { {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA}, {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA}, {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA}, - {"echde_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA}, + {"ecdhe_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA}, {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA}, {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA}, {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, @@ -180,16 +179,35 @@ static const cipher_s cipherlist[] = { {"ecdhe_rsa_aes_128_gcm_sha_256", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, {"ecdh_rsa_aes_128_gcm_sha_256", TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256}, #endif +#ifdef TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + /* cipher suites using SHA384 */ + {"rsa_aes_256_gcm_sha_384", TLS_RSA_WITH_AES_256_GCM_SHA384}, + {"dhe_rsa_aes_256_gcm_sha_384", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384}, + {"dhe_dss_aes_256_gcm_sha_384", TLS_DHE_DSS_WITH_AES_256_GCM_SHA384}, + {"ecdhe_ecdsa_aes_256_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384}, + {"ecdhe_rsa_aes_256_sha_384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384}, + {"ecdhe_ecdsa_aes_256_gcm_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384}, + {"ecdhe_rsa_aes_256_gcm_sha_384", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384}, +#endif +#ifdef TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 + /* chacha20-poly1305 cipher suites */ + {"ecdhe_rsa_chacha20_poly1305_sha_256", + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, + {"ecdhe_ecdsa_chacha20_poly1305_sha_256", + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256}, + {"dhe_rsa_chacha20_poly1305_sha_256", + TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256}, +#endif }; -static const char* pem_library = "libnsspem.so"; -SECMODModule* mod = NULL; +static const char *pem_library = "libnsspem.so"; +static SECMODModule *mod = NULL; /* NSPR I/O layer we use to detect blocking direction during SSL handshake */ static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER; static PRIOMethods nspr_io_methods; -static const char* nss_error_to_name(PRErrorCode code) +static const char *nss_error_to_name(PRErrorCode code) { const char *name = PR_ErrorToName(code); if(name) @@ -198,12 +216,12 @@ static const char* nss_error_to_name(PRErrorCode code) return "unknown error"; } -static void nss_print_error_message(struct SessionHandle *data, PRUint32 err) +static void nss_print_error_message(struct Curl_easy *data, PRUint32 err) { failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT)); } -static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model, +static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model, char *cipher_list) { unsigned int i; @@ -236,14 +254,15 @@ static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model, while((*cipher) && (ISSPACE(*cipher))) ++cipher; - if((cipher_list = strchr(cipher, ','))) { + cipher_list = strchr(cipher, ','); + if(cipher_list) { *cipher_list++ = '\0'; } found = PR_FALSE; for(i=0; iset.str[cert_kind]; const char *n; if(!is_file(str)) @@ -340,6 +358,19 @@ static char* dup_nickname(struct SessionHandle *data, enum dupstring cert_kind) return NULL; } +/* Lock/unlock wrapper for PK11_FindSlotByName() to work around race condition + * in nssSlot_IsTokenPresent() causing spurious SEC_ERROR_NO_TOKEN. For more + * details, go to . + */ +static PK11SlotInfo* nss_find_slot_by_name(const char *slot_name) +{ + PK11SlotInfo *slot; + PR_Lock(nss_findslot_lock); + slot = PK11_FindSlotByName(slot_name); + PR_Unlock(nss_findslot_lock); + return slot; +} + /* Call PK11_CreateGenericObject() with the given obj_class and filename. If * the call succeeds, append the object handle to the list of objects so that * the object can be destroyed in Curl_nss_close(). */ @@ -362,7 +393,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl, if(!slot_name) return CURLE_OUT_OF_MEMORY; - slot = PK11_FindSlotByName(slot_name); + slot = nss_find_slot_by_name(slot_name); free(slot_name); if(!slot) return result; @@ -483,7 +514,7 @@ static CURLcode nss_cache_crl(SECItem *crl_der) return CURLE_OK; } -static CURLcode nss_load_crl(const char* crlfilename) +static CURLcode nss_load_crl(const char *crlfilename) { PRFileDesc *infile; PRFileInfo info; @@ -509,7 +540,7 @@ static CURLcode nss_load_crl(const char* crlfilename) goto fail; /* place a trailing zero right after the visible data */ - body = (char*)filedata.data; + body = (char *)filedata.data; body[--filedata.len] = '\0'; body = strstr(body, "-----BEGIN"); @@ -554,6 +585,7 @@ static CURLcode nss_load_key(struct connectdata *conn, int sockindex, SECStatus status; CURLcode result; struct ssl_connect_data *ssl = conn->ssl; + struct Curl_easy *data = conn->data; (void)sockindex; /* unused */ @@ -563,7 +595,7 @@ static CURLcode nss_load_key(struct connectdata *conn, int sockindex, return result; } - slot = PK11_FindSlotByName("PEM Token #1"); + slot = nss_find_slot_by_name("PEM Token #1"); if(!slot) return CURLE_SSL_CERTPROBLEM; @@ -571,8 +603,7 @@ static CURLcode nss_load_key(struct connectdata *conn, int sockindex, SECMOD_WaitForAnyTokenEvent(mod, 0, 0); PK11_IsPresent(slot); - status = PK11_Authenticate(slot, PR_TRUE, - conn->data->set.str[STRING_KEY_PASSWD]); + status = PK11_Authenticate(slot, PR_TRUE, SSL_SET_OPTION(key_passwd)); PK11_FreeSlot(slot); return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM; @@ -597,7 +628,7 @@ static int display_error(struct connectdata *conn, PRInt32 err, static CURLcode cert_stuff(struct connectdata *conn, int sockindex, char *cert_file, char *key_file) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result; if(cert_file) { @@ -633,7 +664,7 @@ static CURLcode cert_stuff(struct connectdata *conn, int sockindex, return CURLE_OK; } -static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg) +static char *nss_get_password(PK11SlotInfo *slot, PRBool retry, void *arg) { (void)slot; /* unused */ @@ -651,7 +682,7 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig, struct connectdata *conn = (struct connectdata *)arg; #ifdef SSL_ENABLE_OCSP_STAPLING - if(conn->data->set.ssl.verifystatus) { + if(SSL_CONN_CONFIG(verifystatus)) { SECStatus cacheResult; const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd); @@ -677,7 +708,7 @@ static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig, } #endif - if(!conn->data->set.ssl.verifypeer) { + if(!SSL_CONN_CONFIG(verifypeer)) { infof(conn->data, "skipping SSL peer certificate verification\n"); return SECSuccess; } @@ -703,6 +734,11 @@ static void HandshakeCallback(PRFileDesc *sock, void *arg) if(SSL_GetNextProto(sock, &state, buf, &buflen, buflenmax) == SECSuccess) { switch(state) { +#if NSSVERNUM >= 0x031a00 /* 3.26.0 */ + /* used by NSS internally to implement 0-RTT */ + case SSL_NEXT_PROTO_EARLY_VALUE: + /* fall through! */ +#endif case SSL_NEXT_PROTO_NO_SUPPORT: case SSL_NEXT_PROTO_NO_OVERLAP: infof(conn->data, "ALPN/NPN, server did not agree to a protocol\n"); @@ -736,7 +772,7 @@ static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data, PRBool *canFalseStart) { struct connectdata *conn = client_data; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; SSLChannelInfo channelInfo; SSLCipherSuiteInfo cipherInfo; @@ -791,7 +827,7 @@ end: } #endif -static void display_cert_info(struct SessionHandle *data, +static void display_cert_info(struct Curl_easy *data, CERTCertificate *cert) { char *subject, *issuer, *common_name; @@ -892,14 +928,17 @@ static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock) static SECStatus BadCertHandler(void *arg, PRFileDesc *sock) { struct connectdata *conn = (struct connectdata *)arg; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; PRErrorCode err = PR_GetError(); CERTCertificate *cert; /* remember the cert verification result */ - data->set.ssl.certverifyresult = err; + if(SSL_IS_PROXY()) + data->set.proxy_ssl.certverifyresult = err; + else + data->set.ssl.certverifyresult = err; - if(err == SSL_ERROR_BAD_CERT_DOMAIN && !data->set.ssl.verifyhost) + if(err == SSL_ERROR_BAD_CERT_DOMAIN && !SSL_CONN_CONFIG(verifyhost)) /* we are asked not to verify the host name */ return SECSuccess; @@ -950,7 +989,7 @@ static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl, const char *pinnedpubkey) { CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; - struct SessionHandle *data = connssl->data; + struct Curl_easy *data = connssl->data; CERTCertificate *cert; if(!pinnedpubkey) @@ -1002,18 +1041,18 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct SECKEYPrivateKeyStr **pRetKey) { struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; - struct SessionHandle *data = connssl->data; + struct Curl_easy *data = connssl->data; const char *nickname = connssl->client_nickname; + static const char pem_slotname[] = "PEM Token #1"; if(connssl->obj_clicert) { /* use the cert/key provided by PEM reader */ - static const char pem_slotname[] = "PEM Token #1"; SECItem cert_der = { 0, NULL, 0 }; void *proto_win = SSL_RevealPinArg(sock); struct CERTCertificateStr *cert; struct SECKEYPrivateKeyStr *key; - PK11SlotInfo *slot = PK11_FindSlotByName(pem_slotname); + PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname); if(NULL == slot) { failf(data, "NSS: PK11 slot not found: %s", pem_slotname); return SECFailure; @@ -1069,6 +1108,12 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, if(NULL == nickname) nickname = "[unknown]"; + if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) { + failf(data, "NSS: refusing previously loaded certificate from file: %s", + nickname); + return SECFailure; + } + if(NULL == *pRetKey) { failf(data, "NSS: private key not found for certificate: %s", nickname); return SECFailure; @@ -1134,7 +1179,7 @@ static PRStatus nspr_io_close(PRFileDesc *fd) } /* data might be NULL */ -static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir) +static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir) { NSSInitParameters initparams; @@ -1172,7 +1217,7 @@ static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir) } /* data might be NULL */ -static CURLcode nss_init(struct SessionHandle *data) +static CURLcode nss_init(struct Curl_easy *data) { char *cert_dir; struct_stat st; @@ -1243,6 +1288,7 @@ int Curl_nss_init(void) PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256); nss_initlock = PR_NewLock(); nss_crllock = PR_NewLock(); + nss_findslot_lock = PR_NewLock(); } /* We will actually initialize NSS later */ @@ -1251,7 +1297,7 @@ int Curl_nss_init(void) } /* data might be NULL */ -CURLcode Curl_nss_force_init(struct SessionHandle *data) +CURLcode Curl_nss_force_init(struct Curl_easy *data) { CURLcode result; if(!nss_initlock) { @@ -1297,6 +1343,7 @@ void Curl_nss_cleanup(void) PR_DestroyLock(nss_initlock); PR_DestroyLock(nss_crllock); + PR_DestroyLock(nss_findslot_lock); nss_initlock = NULL; initialized = 0; @@ -1328,38 +1375,57 @@ Curl_nss_check_cxn(struct connectdata *conn) return -1; /* connection status unknown */ } -/* - * This function is called when an SSL connection is closed. - */ -void Curl_nss_close(struct connectdata *conn, int sockindex) +static void nss_close(struct ssl_connect_data *connssl) { - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + /* before the cleanup, check whether we are using a client certificate */ + const bool client_cert = (connssl->client_nickname != NULL) + || (connssl->obj_clicert != NULL); + + free(connssl->client_nickname); + connssl->client_nickname = NULL; + + /* destroy all NSS objects in order to avoid failure of NSS shutdown */ + Curl_llist_destroy(connssl->obj_list, NULL); + connssl->obj_list = NULL; + connssl->obj_clicert = NULL; if(connssl->handle) { - /* NSS closes the socket we previously handed to it, so we must mark it - as closed to avoid double close */ - fake_sclose(conn->sock[sockindex]); - conn->sock[sockindex] = CURL_SOCKET_BAD; - - if((connssl->client_nickname != NULL) || (connssl->obj_clicert != NULL)) + if(client_cert) /* A server might require different authentication based on the * particular path being requested by the client. To support this * scenario, we must ensure that a connection will never reuse the * authentication data from a previous connection. */ SSL_InvalidateSession(connssl->handle); - free(connssl->client_nickname); - connssl->client_nickname = NULL; - /* destroy all NSS objects in order to avoid failure of NSS shutdown */ - Curl_llist_destroy(connssl->obj_list, NULL); - connssl->obj_list = NULL; - connssl->obj_clicert = NULL; - PR_Close(connssl->handle); connssl->handle = NULL; } } +/* + * This function is called when an SSL connection is closed. + */ +void Curl_nss_close(struct connectdata *conn, int sockindex) +{ + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex]; + + if(connssl->handle || connssl_proxy->handle) { + /* NSS closes the socket we previously handed to it, so we must mark it + as closed to avoid double close */ + fake_sclose(conn->sock[sockindex]); + conn->sock[sockindex] = CURL_SOCKET_BAD; + } + + if(connssl->handle) + /* nss_close(connssl) will transitively close also connssl_proxy->handle + if both are used. Clear it to avoid a double close leading to crash. */ + connssl_proxy->handle = NULL; + + nss_close(connssl); + nss_close(connssl_proxy); +} + /* return true if NSS can provide error code (and possibly msg) for the error */ static bool is_nss_error(CURLcode err) @@ -1397,9 +1463,9 @@ static Curl_send nss_send; static CURLcode nss_load_ca_certificates(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; - const char *cafile = data->set.ssl.CAfile; - const char *capath = data->set.ssl.CApath; + struct Curl_easy *data = conn->data; + const char *cafile = SSL_CONN_CONFIG(CAfile); + const char *capath = SSL_CONN_CONFIG(CApath); if(cafile) { CURLcode result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE); @@ -1447,13 +1513,22 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn, } static CURLcode nss_init_sslver(SSLVersionRange *sslver, - struct SessionHandle *data) + struct Curl_easy *data, + struct connectdata *conn) { - switch(data->set.ssl.version) { - default: + switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: + /* map CURL_SSLVERSION_DEFAULT to NSS default */ + if(SSL_VersionRangeGetDefault(ssl_variant_stream, sslver) != SECSuccess) + return CURLE_SSL_CONNECT_ERROR; + /* ... but make sure we use at least TLSv1.0 according to libcurl API */ + if(sslver->min < SSL_LIBRARY_VERSION_TLS_1_0) + sslver->min = SSL_LIBRARY_VERSION_TLS_1_0; + return CURLE_OK; + case CURL_SSLVERSION_TLSv1: sslver->min = SSL_LIBRARY_VERSION_TLS_1_0; + /* TODO: set sslver->max to SSL_LIBRARY_VERSION_TLS_1_3 once stable */ #ifdef SSL_LIBRARY_VERSION_TLS_1_2 sslver->max = SSL_LIBRARY_VERSION_TLS_1_2; #elif defined SSL_LIBRARY_VERSION_TLS_1_1 @@ -1493,6 +1568,18 @@ static CURLcode nss_init_sslver(SSLVersionRange *sslver, return CURLE_OK; #endif break; + + case CURL_SSLVERSION_TLSv1_3: +#ifdef SSL_LIBRARY_VERSION_TLS_1_3 + sslver->min = SSL_LIBRARY_VERSION_TLS_1_3; + sslver->max = SSL_LIBRARY_VERSION_TLS_1_3; + return CURLE_OK; +#endif + break; + + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; } failf(data, "TLS minor version cannot be set"); @@ -1500,7 +1587,7 @@ static CURLcode nss_init_sslver(SSLVersionRange *sslver, } static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, - struct SessionHandle *data, + struct Curl_easy *data, CURLcode curlerr) { PRErrorCode err = 0; @@ -1525,13 +1612,14 @@ static CURLcode nss_fail_connect(struct ssl_connect_data *connssl, return curlerr; } -/* Switch the SSL socket into non-blocking mode. */ -static CURLcode nss_set_nonblock(struct ssl_connect_data *connssl, - struct SessionHandle *data) +/* Switch the SSL socket into blocking or non-blocking mode. */ +static CURLcode nss_set_blocking(struct ssl_connect_data *connssl, + struct Curl_easy *data, + bool blocking) { static PRSocketOptionData sock_opt; sock_opt.option = PR_SockOpt_Nonblocking; - sock_opt.value.non_blocking = PR_TRUE; + sock_opt.value.non_blocking = !blocking; if(PR_SetSocketOption(connssl->handle, &sock_opt) != PR_SUCCESS) return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR); @@ -1546,10 +1634,11 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) PRFileDesc *nspr_io_stub = NULL; PRBool ssl_no_cache; PRBool ssl_cbc_random_iv; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CURLcode result; + bool second_layer = FALSE; SSLVersionRange sslver = { SSL_LIBRARY_VERSION_TLS_1_0, /* min */ @@ -1608,18 +1697,18 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) goto error; /* do not use SSL cache if disabled or we are not going to verify peer */ - ssl_no_cache = (conn->ssl_config.sessionid && data->set.ssl.verifypeer) ? - PR_FALSE : PR_TRUE; + ssl_no_cache = (data->set.general_ssl.sessionid + && SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE; if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess) goto error; /* enable/disable the requested SSL version(s) */ - if(nss_init_sslver(&sslver, data) != CURLE_OK) + if(nss_init_sslver(&sslver, data, conn) != CURLE_OK) goto error; if(SSL_VersionRangeSet(model, &sslver) != SECSuccess) goto error; - ssl_cbc_random_iv = !data->set.ssl_enable_beast; + ssl_cbc_random_iv = !SSL_SET_OPTION(enable_beast); #ifdef SSL_CBC_RANDOM_IV /* unless the user explicitly asks to allow the protocol vulnerability, we use the work-around */ @@ -1631,14 +1720,14 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n"); #endif - if(data->set.ssl.cipher_list) { - if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) { + if(SSL_CONN_CONFIG(cipher_list)) { + if(set_ciphers(data, model, SSL_CONN_CONFIG(cipher_list)) != SECSuccess) { result = CURLE_SSL_CIPHER; goto error; } } - if(!data->set.ssl.verifypeer && data->set.ssl.verifyhost) + if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost)) infof(data, "warning: ignoring value of ssl.verifyhost\n"); /* bypass the default SSL_AuthCertificate() hook in case we do not want to @@ -1646,14 +1735,19 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess) goto error; - data->set.ssl.certverifyresult=0; /* not checked yet */ + /* not checked yet */ + if(SSL_IS_PROXY()) + data->set.proxy_ssl.certverifyresult = 0; + else + data->set.ssl.certverifyresult = 0; + if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess) goto error; if(SSL_HandshakeCallback(model, HandshakeCallback, conn) != SECSuccess) goto error; - if(data->set.ssl.verifypeer) { + if(SSL_CONN_CONFIG(verifypeer)) { const CURLcode rv = nss_load_ca_certificates(conn, sockindex); if(rv) { result = rv; @@ -1661,24 +1755,24 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) } } - if(data->set.ssl.CRLfile) { - const CURLcode rv = nss_load_crl(data->set.ssl.CRLfile); + if(SSL_SET_OPTION(CRLfile)) { + const CURLcode rv = nss_load_crl(SSL_SET_OPTION(CRLfile)); if(rv) { result = rv; goto error; } - infof(data, " CRLfile: %s\n", data->set.ssl.CRLfile); + infof(data, " CRLfile: %s\n", SSL_SET_OPTION(CRLfile)); } - if(data->set.str[STRING_CERT]) { - char *nickname = dup_nickname(data, STRING_CERT); + if(SSL_SET_OPTION(cert)) { + char *nickname = dup_nickname(data, SSL_SET_OPTION(cert)); if(nickname) { /* we are not going to use libnsspem.so to read the client cert */ connssl->obj_clicert = NULL; } else { - CURLcode rv = cert_stuff(conn, sockindex, data->set.str[STRING_CERT], - data->set.str[STRING_KEY]); + CURLcode rv = cert_stuff(conn, sockindex, SSL_SET_OPTION(cert), + SSL_SET_OPTION(key)); if(rv) { /* failf() is already done in cert_stuff() */ result = rv; @@ -1698,15 +1792,24 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) goto error; } - /* wrap OS file descriptor by NSPR's file descriptor abstraction */ - nspr_io = PR_ImportTCPSocket(sockfd); - if(!nspr_io) - goto error; + if(conn->proxy_ssl[sockindex].use) { + DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); + DEBUGASSERT(conn->proxy_ssl[sockindex].handle != NULL); + nspr_io = conn->proxy_ssl[sockindex].handle; + second_layer = TRUE; + } + else { + /* wrap OS file descriptor by NSPR's file descriptor abstraction */ + nspr_io = PR_ImportTCPSocket(sockfd); + if(!nspr_io) + goto error; + } /* create our own NSPR I/O layer */ nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods); if(!nspr_io_stub) { - PR_Close(nspr_io); + if(!second_layer) + PR_Close(nspr_io); goto error; } @@ -1715,7 +1818,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) /* push our new layer to the NSPR I/O stack */ if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) { - PR_Close(nspr_io); + if(!second_layer) + PR_Close(nspr_io); PR_Close(nspr_io_stub); goto error; } @@ -1723,7 +1827,8 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) /* import our model socket onto the current I/O stack */ connssl->handle = SSL_ImportFD(model, nspr_io); if(!connssl->handle) { - PR_Close(nspr_io); + if(!second_layer) + PR_Close(nspr_io); goto error; } @@ -1731,12 +1836,12 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) model = NULL; /* This is the password associated with the cert that we're using */ - if(data->set.str[STRING_KEY_PASSWD]) { - SSL_SetPKCS11PinArg(connssl->handle, data->set.str[STRING_KEY_PASSWD]); + if(SSL_SET_OPTION(key_passwd)) { + SSL_SetPKCS11PinArg(connssl->handle, SSL_SET_OPTION(key_passwd)); } #ifdef SSL_ENABLE_OCSP_STAPLING - if(data->set.ssl.verifystatus) { + if(SSL_CONN_CONFIG(verifystatus)) { if(SSL_OptionSet(connssl->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE) != SECSuccess) goto error; @@ -1796,11 +1901,14 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex) goto error; /* propagate hostname to the TLS layer */ - if(SSL_SetURL(connssl->handle, conn->host.name) != SECSuccess) + if(SSL_SetURL(connssl->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name) != SECSuccess) goto error; /* prevent NSS from re-using the session for a different hostname */ - if(SSL_SetSockPeerID(connssl->handle, conn->host.name) != SECSuccess) + if(SSL_SetSockPeerID(connssl->handle, SSL_IS_PROXY() ? + conn->http_proxy.host.name : conn->host.name) + != SECSuccess) goto error; return CURLE_OK; @@ -1815,9 +1923,15 @@ error: static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; CURLcode result = CURLE_SSL_CONNECT_ERROR; PRUint32 timeout; + long * const certverifyresult = SSL_IS_PROXY() ? + &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; + const char * const pinnedpubkey = SSL_IS_PROXY() ? + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : + data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; + /* check timeout situation */ const long time_left = Curl_timeleft(data, NULL, TRUE); @@ -1833,9 +1947,9 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) if(PR_GetError() == PR_WOULD_BLOCK_ERROR) /* blocking direction is updated by nss_update_connecting_state() */ return CURLE_AGAIN; - else if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN) + else if(*certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN) result = CURLE_PEER_FAILED_VERIFICATION; - else if(conn->data->set.ssl.certverifyresult!=0) + else if(*certverifyresult != 0) result = CURLE_SSL_CACERT; goto error; } @@ -1844,11 +1958,11 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) if(result) goto error; - if(data->set.str[STRING_SSL_ISSUERCERT]) { + if(SSL_SET_OPTION(issuercert)) { SECStatus ret = SECFailure; - char *nickname = dup_nickname(data, STRING_SSL_ISSUERCERT); + char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert)); if(nickname) { - /* we support only nicknames in case of STRING_SSL_ISSUERCERT for now */ + /* we support only nicknames in case of issuercert for now */ ret = check_issuer_cert(connssl->handle, nickname); free(nickname); } @@ -1863,7 +1977,7 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex) } } - result = cmp_peer_pubkey(connssl, data->set.str[STRING_SSL_PINNEDPUBLICKEY]); + result = cmp_peer_pubkey(connssl, pinnedpubkey); if(result) /* status already printed */ goto error; @@ -1878,12 +1992,15 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, bool *done) { struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; const bool blocking = (done == NULL); CURLcode result; - if(connssl->state == ssl_connection_complete) + if(connssl->state == ssl_connection_complete) { + if(!blocking) + *done = TRUE; return CURLE_OK; + } if(connssl->connecting_state == ssl_connect_1) { result = nss_setup_connect(conn, sockindex); @@ -1891,16 +2008,14 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, /* we do not expect CURLE_AGAIN from nss_setup_connect() */ return result; - if(!blocking) { - /* in non-blocking mode, set NSS non-blocking mode before handshake */ - result = nss_set_nonblock(connssl, data); - if(result) - return result; - } - connssl->connecting_state = ssl_connect_2; } + /* enable/disable blocking mode before handshake */ + result = nss_set_blocking(connssl, data, blocking); + if(result) + return result; + result = nss_do_connect(conn, sockindex); switch(result) { case CURLE_OK: @@ -1916,7 +2031,7 @@ static CURLcode nss_connect_common(struct connectdata *conn, int sockindex, if(blocking) { /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */ - result = nss_set_nonblock(connssl, data); + result = nss_set_blocking(connssl, data, /* blocking */ FALSE); if(result) return result; } @@ -2015,24 +2130,24 @@ size_t Curl_nss_version(char *buffer, size_t size) } /* data might be NULL */ -int Curl_nss_seed(struct SessionHandle *data) +int Curl_nss_seed(struct Curl_easy *data) { /* make sure that NSS is initialized */ return !!Curl_nss_force_init(data); } /* data might be NULL */ -int Curl_nss_random(struct SessionHandle *data, - unsigned char *entropy, - size_t length) +CURLcode Curl_nss_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length) { Curl_nss_seed(data); /* Initiate the seed if not already done */ if(SECSuccess != PK11_GenerateRandom(entropy, curlx_uztosi(length))) /* signal a failure */ - return -1; + return CURLE_FAILED_INIT; - return 0; + return CURLE_OK; } void Curl_nss_md5sum(unsigned char *tmp, /* input */ @@ -2070,7 +2185,8 @@ bool Curl_nss_cert_status_request(void) #endif } -bool Curl_nss_false_start(void) { +bool Curl_nss_false_start(void) +{ #if NSSVERNUM >= 0x030f04 /* 3.15.4 */ return TRUE; #else diff --git a/contrib/curl/lib/vtls/nssg.h b/contrib/curl/lib/vtls/nssg.h index e388ec0f..8c46929f 100644 --- a/contrib/curl/lib/vtls/nssg.h +++ b/contrib/curl/lib/vtls/nssg.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -42,14 +42,14 @@ void Curl_nss_cleanup(void); size_t Curl_nss_version(char *buffer, size_t size); int Curl_nss_check_cxn(struct connectdata *cxn); -int Curl_nss_seed(struct SessionHandle *data); +int Curl_nss_seed(struct Curl_easy *data); /* initialize NSS library if not already */ -CURLcode Curl_nss_force_init(struct SessionHandle *data); +CURLcode Curl_nss_force_init(struct Curl_easy *data); -int Curl_nss_random(struct SessionHandle *data, - unsigned char *entropy, - size_t length); +CURLcode Curl_nss_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length); void Curl_nss_md5sum(unsigned char *tmp, /* input */ size_t tmplen, @@ -65,6 +65,9 @@ bool Curl_nss_cert_status_request(void); bool Curl_nss_false_start(void); +/* Support HTTPS-proxy */ +#define HTTPS_PROXY_SUPPORT 1 + /* Set the API backend definition to NSS */ #define CURL_SSL_BACKEND CURLSSLBACKEND_NSS diff --git a/contrib/curl/lib/vtls/openssl.c b/contrib/curl/lib/vtls/openssl.c index 3a4bde5b..eb625fe9 100644 --- a/contrib/curl/lib/vtls/openssl.c +++ b/contrib/curl/lib/vtls/openssl.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -46,10 +46,9 @@ #include "openssl.h" #include "connect.h" #include "slist.h" -#include "strequal.h" #include "select.h" #include "vtls.h" -#include "rawstr.h" +#include "strcase.h" #include "hostcheck.h" #include "curl_printf.h" @@ -95,11 +94,6 @@ #if (OPENSSL_VERSION_NUMBER >= 0x10000000L) #define HAVE_ERR_REMOVE_THREAD_STATE 1 -#if (OPENSSL_VERSION_NUMBER >= 0x10100004L) && \ - !defined(LIBRESSL_VERSION_NUMBER) -/* OpenSSL 1.1.0 deprecates the function */ -#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1 -#endif #endif #if !defined(HAVE_SSLV2_CLIENT_METHOD) || \ @@ -110,11 +104,28 @@ #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \ !defined(LIBRESSL_VERSION_NUMBER) -#define SSLeay_add_ssl_algorithms() SSL_library_init() #define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER #define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */ #define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */ #define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */ +#define CONST_EXTS const +#define CONST_ASN1_BIT_STRING const +#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1 +#else +/* For OpenSSL before 1.1.0 */ +#define ASN1_STRING_get0_data(x) ASN1_STRING_data(x) +#define X509_get0_notBefore(x) X509_get_notBefore(x) +#define X509_get0_notAfter(x) X509_get_notAfter(x) +#define CONST_EXTS /* nope */ +#define CONST_ASN1_BIT_STRING /* nope */ +#ifdef LIBRESSL_VERSION_NUMBER +static unsigned long OpenSSL_version_num(void) +{ + return LIBRESSL_VERSION_NUMBER; +} +#else +#define OpenSSL_version_num() SSLeay() +#endif #endif #if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \ @@ -122,6 +133,12 @@ #define HAVE_X509_GET0_SIGNATURE 1 #endif +#if OPENSSL_VERSION_NUMBER >= 0x10002003L && \ + OPENSSL_VERSION_NUMBER <= 0x10002FFFL && \ + !defined(OPENSSL_NO_COMP) +#define HAVE_SSL_COMP_FREE_COMPRESSION_METHODS 1 +#endif + #if (OPENSSL_VERSION_NUMBER < 0x0090808fL) /* not present in older OpenSSL */ #define OPENSSL_load_builtin_modules(x) @@ -159,39 +176,34 @@ static int passwd_callback(char *buf, int num, int encrypting, } /* - * rand_enough() is a function that returns TRUE if we have seeded the random - * engine properly. We use some preprocessor magic to provide a seed_enough() - * macro to use, just to prevent a compiler warning on this function if we - * pass in an argument that is never used. + * rand_enough() returns TRUE if we have seeded the random engine properly. */ - -#ifdef HAVE_RAND_STATUS -#define seed_enough(x) rand_enough() static bool rand_enough(void) { return (0 != RAND_status()) ? TRUE : FALSE; } -#else -#define seed_enough(x) rand_enough(x) -static bool rand_enough(int nread) -{ - /* this is a very silly decision to make */ - return (nread > 500) ? TRUE : FALSE; -} -#endif -static int ossl_seed(struct SessionHandle *data) +static CURLcode Curl_ossl_seed(struct Curl_easy *data) { + /* we have the "SSL is seeded" boolean static to prevent multiple + time-consuming seedings in vain */ + static bool ssl_seeded = FALSE; char *buf = data->state.buffer; /* point to the big buffer */ int nread=0; - /* Q: should we add support for a random file name as a libcurl option? - A: Yes, it is here */ + if(ssl_seeded) + return CURLE_OK; + + if(rand_enough()) { + /* OpenSSL 1.1.0+ will return here */ + ssl_seeded = TRUE; + return CURLE_OK; + } #ifndef RANDOM_FILE /* if RANDOM_FILE isn't defined, we only perform this if an option tells us to! */ - if(data->set.ssl.random_file) + if(data->set.str[STRING_SSL_RANDOM_FILE]) #define RANDOM_FILE "" /* doesn't matter won't be used */ #endif { @@ -200,7 +212,7 @@ static int ossl_seed(struct SessionHandle *data) data->set.str[STRING_SSL_RANDOM_FILE]: RANDOM_FILE), RAND_LOAD_LENGTH); - if(seed_enough(nread)) + if(rand_enough()) return nread; } @@ -220,7 +232,7 @@ static int ossl_seed(struct SessionHandle *data) data->set.str[STRING_SSL_EGDSOCKET]:EGD_SOCKET); if(-1 != ret) { nread += ret; - if(seed_enough(nread)) + if(rand_enough()) return nread; } } @@ -231,9 +243,10 @@ static int ossl_seed(struct SessionHandle *data) do { unsigned char randb[64]; int len = sizeof(randb); - RAND_bytes(randb, len); + if(!RAND_bytes(randb, len)) + break; RAND_add(randb, len, (len >> 1)); - } while(!RAND_status()); + } while(!rand_enough()); /* generates a default path for the random seed file */ buf[0]=0; /* blank it first */ @@ -241,25 +254,12 @@ static int ossl_seed(struct SessionHandle *data) if(buf[0]) { /* we got a file name to try */ nread += RAND_load_file(buf, RAND_LOAD_LENGTH); - if(seed_enough(nread)) + if(rand_enough()) return nread; } infof(data, "libcurl is now using a weak random seed!\n"); - return nread; -} - -static void Curl_ossl_seed(struct SessionHandle *data) -{ - /* we have the "SSL is seeded" boolean static to prevent multiple - time-consuming seedings in vain */ - static bool ssl_seeded = FALSE; - - if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] || - data->set.str[STRING_SSL_EGDSOCKET]) { - ossl_seed(data); - ssl_seeded = TRUE; - } + return CURLE_SSL_CONNECT_ERROR; /* confusing error code */ } #ifndef SSL_FILETYPE_ENGINE @@ -272,13 +272,13 @@ static int do_file_type(const char *type) { if(!type || !type[0]) return SSL_FILETYPE_PEM; - if(Curl_raw_equal(type, "PEM")) + if(strcasecompare(type, "PEM")) return SSL_FILETYPE_PEM; - if(Curl_raw_equal(type, "DER")) + if(strcasecompare(type, "DER")) return SSL_FILETYPE_ASN1; - if(Curl_raw_equal(type, "ENG")) + if(strcasecompare(type, "ENG")) return SSL_FILETYPE_ENGINE; - if(Curl_raw_equal(type, "P12")) + if(strcasecompare(type, "P12")) return SSL_FILETYPE_PKCS12; return -1; } @@ -295,7 +295,7 @@ static int ssl_ui_reader(UI *ui, UI_STRING *uis) switch(UI_get_string_type(uis)) { case UIT_PROMPT: case UIT_VERIFY: - password = (const char*)UI_get0_user_data(ui); + password = (const char *)UI_get0_user_data(ui); if(password && (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) { UI_set_result(ui, uis, password); return 1; @@ -331,9 +331,10 @@ int cert_stuff(struct connectdata *conn, char *cert_file, const char *cert_type, char *key_file, - const char *key_type) + const char *key_type, + char *key_passwd) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int file_type = do_file_type(cert_type); @@ -342,10 +343,9 @@ int cert_stuff(struct connectdata *conn, X509 *x509; int cert_done = 0; - if(data->set.str[STRING_KEY_PASSWD]) { + if(key_passwd) { /* set the password in the callback userdata */ - SSL_CTX_set_default_passwd_cb_userdata(ctx, - data->set.str[STRING_KEY_PASSWD]); + SSL_CTX_set_default_passwd_cb_userdata(ctx, key_passwd); /* Set passwd callback: */ SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); } @@ -456,7 +456,7 @@ int cert_stuff(struct connectdata *conn, PKCS12_PBE_add(); - if(!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509, + if(!PKCS12_parse(p12, key_passwd, &pri, &x509, &ca)) { failf(data, "could not parse PKCS12 file, check password, " OSSL_PACKAGE @@ -493,23 +493,21 @@ int cert_stuff(struct connectdata *conn, /* * Note that sk_X509_pop() is used below to make sure the cert is * removed from the stack properly before getting passed to - * SSL_CTX_add_extra_chain_cert(). Previously we used - * sk_X509_value() instead, but then we'd clean it in the subsequent - * sk_X509_pop_free() call. + * SSL_CTX_add_extra_chain_cert(), which takes ownership. Previously + * we used sk_X509_value() instead, but then we'd clean it in the + * subsequent sk_X509_pop_free() call. */ X509 *x = sk_X509_pop(ca); + if(!SSL_CTX_add_client_CA(ctx, x)) { + X509_free(x); + failf(data, "cannot add certificate to client CA list"); + goto fail; + } if(!SSL_CTX_add_extra_chain_cert(ctx, x)) { X509_free(x); failf(data, "cannot add certificate to certificate chain"); goto fail; } - /* SSL_CTX_add_client_CA() seems to work with either sk_* function, - * presumably because it duplicates what we pass to it. - */ - if(!SSL_CTX_add_client_CA(ctx, x)) { - failf(data, "cannot add certificate to client CA list"); - goto fail; - } } } @@ -554,7 +552,7 @@ int cert_stuff(struct connectdata *conn, EVP_PKEY *priv_key = NULL; if(data->state.engine) { UI_METHOD *ui_method = - UI_create_method((char *)"cURL user interface"); + UI_create_method((char *)"curl user interface"); if(!ui_method) { failf(data, "unable do create " OSSL_PACKAGE " user-interface method"); @@ -568,7 +566,7 @@ int cert_stuff(struct connectdata *conn, priv_key = (EVP_PKEY *) ENGINE_load_private_key(data->state.engine, key_file, ui_method, - data->set.str[STRING_KEY_PASSWD]); + key_passwd); UI_destroy_method(ui_method); if(!priv_key) { failf(data, "failed to load private key from crypto engine"); @@ -666,7 +664,7 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size) /* Return error string for last OpenSSL error */ -static char *SSL_strerror(unsigned long error, char *buf, size_t size) +static char *ossl_strerror(unsigned long error, char *buf, size_t size) { /* OpenSSL 0.9.6 and later has a function named ERR_error_string_n() that takes the size of the buffer as a @@ -705,6 +703,10 @@ int Curl_ossl_init(void) CONF_MFLAGS_DEFAULT_SECTION| CONF_MFLAGS_IGNORE_MISSING_FILE); +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ + !defined(LIBRESSL_VERSION_NUMBER) + /* OpenSSL 1.1.0+ takes care of initialization itself */ +#else /* Lets get nice error messages */ SSL_load_error_strings(); @@ -713,6 +715,7 @@ int Curl_ossl_init(void) return 0; OpenSSL_add_all_algorithms(); +#endif return 1; } @@ -720,6 +723,11 @@ int Curl_ossl_init(void) /* Global cleanup */ void Curl_ossl_cleanup(void) { +#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ + !defined(LIBRESSL_VERSION_NUMBER) + /* OpenSSL 1.1 deprecates all these cleanup functions and + turns them into no-ops in OpenSSL 1.0 compatibility mode */ +#else /* Free ciphers and digests lists */ EVP_cleanup(); @@ -728,18 +736,11 @@ void Curl_ossl_cleanup(void) ENGINE_cleanup(); #endif -#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA - /* Free OpenSSL ex_data table */ - CRYPTO_cleanup_all_ex_data(); -#endif - /* Free OpenSSL error strings */ ERR_free_strings(); /* Free thread local error state, destroying hash upon zero refcount */ -#ifdef HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED - -#elif defined(HAVE_ERR_REMOVE_THREAD_STATE) +#ifdef HAVE_ERR_REMOVE_THREAD_STATE ERR_remove_thread_state(NULL); #else ERR_remove_state(0); @@ -748,10 +749,10 @@ void Curl_ossl_cleanup(void) /* Free all memory allocated by all configuration modules */ CONF_modules_free(); -#if OPENSSL_VERSION_NUMBER >= 0x10002003L && \ - OPENSSL_VERSION_NUMBER <= 0x10002FFFL +#ifdef HAVE_SSL_COMP_FREE_COMPRESSION_METHODS SSL_COMP_free_compression_methods(); #endif +#endif } /* @@ -808,7 +809,7 @@ int Curl_ossl_check_cxn(struct connectdata *conn) /* Selects an OpenSSL crypto engine */ -CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine) +CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine) { #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) ENGINE *e; @@ -839,7 +840,7 @@ CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine) ENGINE_free(e); failf(data, "Failed to initialise SSL Engine '%s':\n%s", - engine, SSL_strerror(ERR_get_error(), buf, sizeof(buf))); + engine, ossl_strerror(ERR_get_error(), buf, sizeof(buf))); return CURLE_SSL_ENGINE_INITFAILED; } data->state.engine = e; @@ -853,7 +854,7 @@ CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine) /* Sets engine as default for all SSL operations */ -CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data) +CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data) { #ifdef HAVE_OPENSSL_ENGINE_H if(data->state.engine) { @@ -875,7 +876,7 @@ CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data) /* Return list of OpenSSL crypto engine names. */ -struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data) +struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data) { struct curl_slist *list = NULL; #if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H) @@ -896,24 +897,28 @@ struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data) } +static void ossl_close(struct ssl_connect_data *connssl) +{ + if(connssl->handle) { + (void)SSL_shutdown(connssl->handle); + SSL_set_connect_state(connssl->handle); + + SSL_free(connssl->handle); + connssl->handle = NULL; + } + if(connssl->ctx) { + SSL_CTX_free(connssl->ctx); + connssl->ctx = NULL; + } +} + /* * This function is called when an SSL connection is closed. */ void Curl_ossl_close(struct connectdata *conn, int sockindex) { - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - if(connssl->handle) { - (void)SSL_shutdown(connssl->handle); - SSL_set_connect_state(connssl->handle); - - SSL_free (connssl->handle); - connssl->handle = NULL; - } - if(connssl->ctx) { - SSL_CTX_free (connssl->ctx); - connssl->ctx = NULL; - } + ossl_close(&conn->ssl[sockindex]); + ossl_close(&conn->proxy_ssl[sockindex]); } /* @@ -924,9 +929,9 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) { int retval = 0; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; - char buf[120]; /* We will use this for the OpenSSL error buffer, so it has - to be at least 120 bytes long. */ + struct Curl_easy *data = conn->data; + char buf[256]; /* We will use this for the OpenSSL error buffer, so it has + to be at least 256 bytes long. */ unsigned long sslerror; ssize_t nread; int buffsize; @@ -944,8 +949,8 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) if(connssl->handle) { buffsize = (int)sizeof(buf); while(!done) { - int what = Curl_socket_ready(conn->sock[sockindex], - CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); + int what = SOCKET_READABLE(conn->sock[sockindex], + SSL_SHUTDOWN_TIMEOUT); if(what > 0) { ERR_clear_error(); @@ -975,7 +980,7 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) /* openssl/ssl.h says "look at error stack/return value/errno" */ sslerror = ERR_get_error(); failf(conn->data, OSSL_PACKAGE " SSL read: %s, errno %d", - ERR_error_string(sslerror, buf), + ossl_strerror(sslerror, buf, sizeof(buf)), SOCKERRNO); done = 1; break; @@ -1011,7 +1016,7 @@ int Curl_ossl_shutdown(struct connectdata *conn, int sockindex) #endif } - SSL_free (connssl->handle); + SSL_free(connssl->handle); connssl->handle = NULL; } return retval; @@ -1027,7 +1032,7 @@ void Curl_ossl_session_free(void *ptr) * This function is called when the 'data' struct is going away. Close * down everything and free all resources! */ -void Curl_ossl_close_all(struct SessionHandle *data) +void Curl_ossl_close_all(struct Curl_easy *data) { #ifdef HAVE_OPENSSL_ENGINE_H if(data->state.engine) { @@ -1038,6 +1043,14 @@ void Curl_ossl_close_all(struct SessionHandle *data) #else (void)data; #endif +#if !defined(HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED) && \ + defined(HAVE_ERR_REMOVE_THREAD_STATE) + /* OpenSSL 1.0.1 and 1.0.2 build an error queue that is stored per-thread + so we need to clean it here in case the thread will be killed. All OpenSSL + code should extract the error in association with the error so clearing + this queue here should be harmless at worst. */ + ERR_remove_thread_state(NULL); +#endif } /* ====================================================== */ @@ -1069,7 +1082,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) bool matched = FALSE; int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */ size_t addrlen = 0; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; STACK_OF(GENERAL_NAME) *altnames; #ifdef ENABLE_IPV6 struct in6_addr addr; @@ -1077,16 +1090,22 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) struct in_addr addr; #endif CURLcode result = CURLE_OK; + bool dNSName = FALSE; /* if a dNSName field exists in the cert */ + bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */ + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; + const char * const dispname = SSL_IS_PROXY() ? + conn->http_proxy.host.dispname : conn->host.dispname; #ifdef ENABLE_IPV6 if(conn->bits.ipv6_ip && - Curl_inet_pton(AF_INET6, conn->host.name, &addr)) { + Curl_inet_pton(AF_INET6, hostname, &addr)) { target = GEN_IPADD; addrlen = sizeof(struct in6_addr); } else #endif - if(Curl_inet_pton(AF_INET, conn->host.name, &addr)) { + if(Curl_inet_pton(AF_INET, hostname, &addr)) { target = GEN_IPADD; addrlen = sizeof(struct in_addr); } @@ -1097,20 +1116,27 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) if(altnames) { int numalts; int i; + bool dnsmatched = FALSE; + bool ipmatched = FALSE; /* get amount of alternatives, RFC2459 claims there MUST be at least one, but we don't depend on it... */ numalts = sk_GENERAL_NAME_num(altnames); - /* loop through all alternatives while none has matched */ - for(i=0; (itype == GEN_DNS) + dNSName = TRUE; + else if(check->type == GEN_IPADD) + iPAddress = TRUE; + /* only check alternatives of the same type the target is */ if(check->type == target) { /* get data and length */ - const char *altptr = (char *)ASN1_STRING_data(check->d.ia5); + const char *altptr = (char *)ASN1_STRING_get0_data(check->d.ia5); size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5); switch(target) { @@ -1128,11 +1154,11 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) if((altlen == strlen(altptr)) && /* if this isn't true, there was an embedded zero in the name string and we cannot match it. */ - Curl_cert_hostcheck(altptr, conn->host.name)) { - matched = TRUE; + Curl_cert_hostcheck(altptr, hostname)) { + dnsmatched = TRUE; infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"\n", - conn->host.dispname, altptr); + dispname, altptr); } break; @@ -1140,27 +1166,28 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) /* compare alternative IP address if the data chunk is the same size our server IP address is */ if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) { - matched = TRUE; + ipmatched = TRUE; infof(data, " subjectAltName: host \"%s\" matched cert's IP address!\n", - conn->host.dispname); + dispname); } break; } } } GENERAL_NAMES_free(altnames); + + if(dnsmatched || ipmatched) + matched = TRUE; } if(matched) /* an alternative name matched */ ; - else if(altnames) { - /* an alternative name field existed, but didn't match and then we MUST - fail */ - infof(data, " subjectAltName does not match %s\n", conn->host.dispname); + else if(dNSName || iPAddress) { + infof(data, " subjectAltName does not match %s\n", dispname); failf(data, "SSL: no alternative certificate subject name matches " - "target host name '%s'", conn->host.dispname); + "target host name '%s'", dispname); result = CURLE_PEER_FAILED_VERIFICATION; } else { @@ -1197,7 +1224,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) if(j >= 0) { peer_CN = OPENSSL_malloc(j+1); if(peer_CN) { - memcpy(peer_CN, ASN1_STRING_data(tmp), j); + memcpy(peer_CN, ASN1_STRING_get0_data(tmp), j); peer_CN[j] = '\0'; } } @@ -1234,9 +1261,9 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) "SSL: unable to obtain common name from peer certificate"); result = CURLE_PEER_FAILED_VERIFICATION; } - else if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) { + else if(!Curl_cert_hostcheck((const char *)peer_CN, hostname)) { failf(data, "SSL: certificate subject name '%s' does not match " - "target host name '%s'", peer_CN, conn->host.dispname); + "target host name '%s'", peer_CN, dispname); result = CURLE_PEER_FAILED_VERIFICATION; } else { @@ -1257,7 +1284,7 @@ static CURLcode verifystatus(struct connectdata *conn, int i, ocsp_status; const unsigned char *p; CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; OCSP_RESPONSE *rsp = NULL; OCSP_BASICRESP *br = NULL; @@ -1387,7 +1414,7 @@ static const char *ssl_msg_type(int ssl_ver, int msg) { #ifdef SSL2_VERSION_MAJOR if(ssl_ver == SSL2_VERSION_MAJOR) { - switch (msg) { + switch(msg) { case SSL2_MT_ERROR: return "Error"; case SSL2_MT_CLIENT_HELLO: @@ -1411,7 +1438,7 @@ static const char *ssl_msg_type(int ssl_ver, int msg) else #endif if(ssl_ver == SSL3_VERSION_MAJOR) { - switch (msg) { + switch(msg) { case SSL3_MT_HELLO_REQUEST: return "Hello request"; case SSL3_MT_CLIENT_HELLO: @@ -1473,7 +1500,7 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, const void *buf, size_t len, SSL *ssl, void *userp) { - struct SessionHandle *data; + struct Curl_easy *data; const char *msg_name, *tls_rt_name; char ssl_buf[1024]; char unknown[32]; @@ -1510,6 +1537,11 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, case TLS1_2_VERSION: verstr = "TLSv1.2"; break; +#endif +#ifdef TLS1_3_VERSION + case TLS1_3_VERSION: + verstr = "TLSv1.3"; + break; #endif case 0: break; @@ -1533,7 +1565,7 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, else tls_rt_name = ""; - msg_type = *(char*)buf; + msg_type = *(char *)buf; msg_name = ssl_msg_type(ssl_ver, msg_type); txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "%s (%s), %s, %s (%d):\n", @@ -1639,6 +1671,10 @@ get_ssl_version_txt(SSL *ssl) return ""; switch(SSL_version(ssl)) { +#ifdef TLS1_3_VERSION + case TLS1_3_VERSION: + return "TLSv1.3"; +#endif #if OPENSSL_VERSION_NUMBER >= 0x1000100FL case TLS1_2_VERSION: return "TLSv1.2"; @@ -1659,9 +1695,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; char *ciphers; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; SSL_METHOD_QUAL SSL_METHOD *req_method = NULL; - void *ssl_sessionid = NULL; X509_LOOKUP *lookup = NULL; curl_socket_t sockfd = conn->sock[sockindex]; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; @@ -1674,23 +1709,39 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) struct in_addr addr; #endif #endif + long * const certverifyresult = SSL_IS_PROXY() ? + &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; + const long int ssl_version = SSL_CONN_CONFIG(version); +#ifdef USE_TLS_SRP + const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype); +#endif + char * const ssl_cert = SSL_SET_OPTION(cert); + const char * const ssl_cert_type = SSL_SET_OPTION(cert_type); + const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile); + const char * const ssl_capath = SSL_CONN_CONFIG(CApath); + const bool verifypeer = SSL_CONN_CONFIG(verifypeer); + const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile); + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; DEBUGASSERT(ssl_connect_1 == connssl->connecting_state); /* Make funny stuff to get random input */ - Curl_ossl_seed(data); + result = Curl_ossl_seed(data); + if(result) + return result; - data->set.ssl.certverifyresult = !X509_V_OK; + *certverifyresult = !X509_V_OK; /* check to see if we've been told to use an explicit SSL/TLS version */ - switch(data->set.ssl.version) { - default: + switch(ssl_version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: case CURL_SSLVERSION_TLSv1_2: + case CURL_SSLVERSION_TLSv1_3: /* it will be handled later with the context options */ #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ !defined(LIBRESSL_VERSION_NUMBER) @@ -1706,7 +1757,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) return CURLE_NOT_BUILT_IN; #else #ifdef USE_TLS_SRP - if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) + if(ssl_authtype == CURL_TLSAUTH_SRP) return CURLE_SSL_CONNECT_ERROR; #endif req_method = SSLv2_client_method(); @@ -1719,13 +1770,16 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) return CURLE_NOT_BUILT_IN; #else #ifdef USE_TLS_SRP - if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) + if(ssl_authtype == CURL_TLSAUTH_SRP) return CURLE_SSL_CONNECT_ERROR; #endif req_method = SSLv3_client_method(); use_sni(FALSE); break; #endif + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; } if(connssl->ctx) @@ -1804,14 +1858,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) #ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS /* unless the user explicitly ask to allow the protocol vulnerability we use the work-around */ - if(!conn->data->set.ssl_enable_beast) + if(!SSL_SET_OPTION(enable_beast)) ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; #endif - switch(data->set.ssl.version) { + switch(ssl_version) { case CURL_SSLVERSION_SSLv3: #ifdef USE_TLS_SRP - if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { + if(ssl_authtype == CURL_TLSAUTH_SRP) { infof(data, "Set version TLSv1.x for SRP authorisation\n"); } #endif @@ -1820,6 +1874,9 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) #if OPENSSL_VERSION_NUMBER >= 0x1000100FL ctx_options |= SSL_OP_NO_TLSv1_1; ctx_options |= SSL_OP_NO_TLSv1_2; +#ifdef TLS1_3_VERSION + ctx_options |= SSL_OP_NO_TLSv1_3; +#endif #endif break; @@ -1835,38 +1892,75 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) #if OPENSSL_VERSION_NUMBER >= 0x1000100FL ctx_options |= SSL_OP_NO_TLSv1_1; ctx_options |= SSL_OP_NO_TLSv1_2; +#ifdef TLS1_3_VERSION + ctx_options |= SSL_OP_NO_TLSv1_3; +#endif #endif break; -#if OPENSSL_VERSION_NUMBER >= 0x1000100FL case CURL_SSLVERSION_TLSv1_1: +#if OPENSSL_VERSION_NUMBER >= 0x1000100FL ctx_options |= SSL_OP_NO_SSLv2; ctx_options |= SSL_OP_NO_SSLv3; ctx_options |= SSL_OP_NO_TLSv1; ctx_options |= SSL_OP_NO_TLSv1_2; +#ifdef TLS1_3_VERSION + ctx_options |= SSL_OP_NO_TLSv1_3; +#endif break; +#else + failf(data, OSSL_PACKAGE " was built without TLS 1.1 support"); + return CURLE_NOT_BUILT_IN; +#endif case CURL_SSLVERSION_TLSv1_2: +#if OPENSSL_VERSION_NUMBER >= 0x1000100FL ctx_options |= SSL_OP_NO_SSLv2; ctx_options |= SSL_OP_NO_SSLv3; ctx_options |= SSL_OP_NO_TLSv1; ctx_options |= SSL_OP_NO_TLSv1_1; +#ifdef TLS1_3_VERSION + ctx_options |= SSL_OP_NO_TLSv1_3; +#endif break; +#else + failf(data, OSSL_PACKAGE " was built without TLS 1.2 support"); + return CURLE_NOT_BUILT_IN; +#endif + + case CURL_SSLVERSION_TLSv1_3: +#ifdef TLS1_3_VERSION + SSL_CTX_set_max_proto_version(connssl->ctx, TLS1_3_VERSION); + ctx_options |= SSL_OP_NO_SSLv2; + ctx_options |= SSL_OP_NO_SSLv3; + ctx_options |= SSL_OP_NO_TLSv1; + ctx_options |= SSL_OP_NO_TLSv1_1; + ctx_options |= SSL_OP_NO_TLSv1_2; + break; +#else + failf(data, OSSL_PACKAGE " was built without TLS 1.3 support"); + return CURLE_NOT_BUILT_IN; #endif -#ifndef OPENSSL_NO_SSL2 case CURL_SSLVERSION_SSLv2: +#ifndef OPENSSL_NO_SSL2 ctx_options |= SSL_OP_NO_SSLv3; ctx_options |= SSL_OP_NO_TLSv1; #if OPENSSL_VERSION_NUMBER >= 0x1000100FL ctx_options |= SSL_OP_NO_TLSv1_1; ctx_options |= SSL_OP_NO_TLSv1_2; +#ifdef TLS1_3_VERSION + ctx_options |= SSL_OP_NO_TLSv1_3; +#endif #endif break; +#else + failf(data, OSSL_PACKAGE " was built without SSLv2 support"); + return CURLE_NOT_BUILT_IN; #endif default: - failf(data, "Unsupported SSL protocol version"); + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); return CURLE_SSL_CONNECT_ERROR; } @@ -1905,19 +1999,16 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) } #endif - if(data->set.str[STRING_CERT] || data->set.str[STRING_CERT_TYPE]) { - if(!cert_stuff(conn, - connssl->ctx, - data->set.str[STRING_CERT], - data->set.str[STRING_CERT_TYPE], - data->set.str[STRING_KEY], - data->set.str[STRING_KEY_TYPE])) { + if(ssl_cert || ssl_cert_type) { + if(!cert_stuff(conn, connssl->ctx, ssl_cert, ssl_cert_type, + SSL_SET_OPTION(key), SSL_SET_OPTION(key_type), + SSL_SET_OPTION(key_passwd))) { /* failf() is already done in cert_stuff() */ return CURLE_SSL_CERTPROBLEM; } } - ciphers = data->set.str[STRING_SSL_CIPHER_LIST]; + ciphers = SSL_CONN_CONFIG(cipher_list); if(!ciphers) ciphers = (char *)DEFAULT_CIPHER_SELECTION; if(!SSL_CTX_set_cipher_list(connssl->ctx, ciphers)) { @@ -1927,18 +2018,20 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) infof(data, "Cipher selection: %s\n", ciphers); #ifdef USE_TLS_SRP - if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) { - infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username); + if(ssl_authtype == CURL_TLSAUTH_SRP) { + char * const ssl_username = SSL_SET_OPTION(username); - if(!SSL_CTX_set_srp_username(connssl->ctx, data->set.ssl.username)) { + infof(data, "Using TLS-SRP username: %s\n", ssl_username); + + if(!SSL_CTX_set_srp_username(connssl->ctx, ssl_username)) { failf(data, "Unable to set SRP user name"); return CURLE_BAD_FUNCTION_ARGUMENT; } - if(!SSL_CTX_set_srp_password(connssl->ctx, data->set.ssl.password)) { + if(!SSL_CTX_set_srp_password(connssl->ctx, SSL_SET_OPTION(password))) { failf(data, "failed setting SRP password"); return CURLE_BAD_FUNCTION_ARGUMENT; } - if(!data->set.str[STRING_SSL_CIPHER_LIST]) { + if(!SSL_CONN_CONFIG(cipher_list)) { infof(data, "Setting cipher list SRP\n"); if(!SSL_CTX_set_cipher_list(connssl->ctx, "SRP")) { @@ -1948,20 +2041,17 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) } } #endif - if(data->set.str[STRING_SSL_CAFILE] || data->set.str[STRING_SSL_CAPATH]) { + + if(ssl_cafile || ssl_capath) { /* tell SSL where to find CA certificates that are used to verify the servers certificate. */ - if(!SSL_CTX_load_verify_locations(connssl->ctx, - data->set.str[STRING_SSL_CAFILE], - data->set.str[STRING_SSL_CAPATH])) { - if(data->set.ssl.verifypeer) { + if(!SSL_CTX_load_verify_locations(connssl->ctx, ssl_cafile, ssl_capath)) { + if(verifypeer) { /* Fail if we insist on successfully verifying the server. */ failf(data, "error setting certificate verify locations:\n" " CAfile: %s\n CApath: %s", - data->set.str[STRING_SSL_CAFILE]? - data->set.str[STRING_SSL_CAFILE]: "none", - data->set.str[STRING_SSL_CAPATH]? - data->set.str[STRING_SSL_CAPATH] : "none"); + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); return CURLE_SSL_CACERT_BADFILE; } else { @@ -1978,29 +2068,25 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) infof(data, " CAfile: %s\n" " CApath: %s\n", - data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]: - "none", - data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]: - "none"); + ssl_cafile ? ssl_cafile : "none", + ssl_capath ? ssl_capath : "none"); } #ifdef CURL_CA_FALLBACK - else if(data->set.ssl.verifypeer) { + else if(verifypeer) { /* verfying the peer without any CA certificates won't work so use openssl's built in default as fallback */ SSL_CTX_set_default_verify_paths(connssl->ctx); } #endif - if(data->set.str[STRING_SSL_CRLFILE]) { + if(ssl_crlfile) { /* tell SSL where to find CRL file that is used to check certificate * revocation */ lookup=X509_STORE_add_lookup(SSL_CTX_get_cert_store(connssl->ctx), X509_LOOKUP_file()); if(!lookup || - (!X509_load_crl_file(lookup, data->set.str[STRING_SSL_CRLFILE], - X509_FILETYPE_PEM)) ) { - failf(data, "error loading CRL file: %s", - data->set.str[STRING_SSL_CRLFILE]); + (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) { + failf(data, "error loading CRL file: %s", ssl_crlfile); return CURLE_SSL_CRL_BADFILE; } else { @@ -2009,9 +2095,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx), X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); } - infof(data, - " CRLfile: %s\n", data->set.str[STRING_SSL_CRLFILE] ? - data->set.str[STRING_SSL_CRLFILE]: "none"); + infof(data, " CRLfile: %s\n", ssl_crlfile); } /* Try building a chain using issuers in the trusted store first to avoid @@ -2022,7 +2106,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest */ #if defined(X509_V_FLAG_TRUSTED_FIRST) && !defined(X509_V_FLAG_NO_ALT_CHAINS) - if(data->set.ssl.verifypeer) { + if(verifypeer) { X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx), X509_V_FLAG_TRUSTED_FIRST); } @@ -2033,8 +2117,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) * anyway. In the latter case the result of the verification is checked with * SSL_get_verify_result() below. */ SSL_CTX_set_verify(connssl->ctx, - data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE, - NULL); + verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL); /* give application a chance to interfere with SSL set up. */ if(data->set.ssl.fsslctx) { @@ -2057,39 +2140,53 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ !defined(OPENSSL_NO_OCSP) - if(data->set.ssl.verifystatus) + if(SSL_CONN_CONFIG(verifystatus)) SSL_set_tlsext_status_type(connssl->handle, TLSEXT_STATUSTYPE_ocsp); #endif SSL_set_connect_state(connssl->handle); connssl->server_cert = 0x0; - #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) && + if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) && #ifdef ENABLE_IPV6 - (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) && + (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) && #endif sni && - !SSL_set_tlsext_host_name(connssl->handle, conn->host.name)) + !SSL_set_tlsext_host_name(connssl->handle, hostname)) infof(data, "WARNING: failed to configure server name indication (SNI) " "TLS extension\n"); #endif /* Check if there's a cached ID we can/should use here! */ - if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { - /* we got a session id, use it! */ - if(!SSL_set_session(connssl->handle, ssl_sessionid)) { - failf(data, "SSL: SSL_set_session failed: %s", - ERR_error_string(ERR_get_error(), NULL)); - return CURLE_SSL_CONNECT_ERROR; + if(data->set.general_ssl.sessionid) { + void *ssl_sessionid = NULL; + + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) { + /* we got a session id, use it! */ + if(!SSL_set_session(connssl->handle, ssl_sessionid)) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "SSL: SSL_set_session failed: %s", + ERR_error_string(ERR_get_error(), NULL)); + return CURLE_SSL_CONNECT_ERROR; + } + /* Informational message */ + infof(data, "SSL re-using session ID\n"); } - /* Informational message */ - infof (data, "SSL re-using session ID\n"); + Curl_ssl_sessionid_unlock(conn); } - /* pass the raw socket into the SSL layers */ - if(!SSL_set_fd(connssl->handle, (int)sockfd)) { + if(conn->proxy_ssl[sockindex].use) { + BIO *const bio = BIO_new(BIO_f_ssl()); + DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state); + DEBUGASSERT(conn->proxy_ssl[sockindex].handle != NULL); + DEBUGASSERT(bio != NULL); + BIO_set_ssl(bio, conn->proxy_ssl[sockindex].handle, FALSE); + SSL_set_bio(connssl->handle, bio, bio); + } + else if(!SSL_set_fd(connssl->handle, (int)sockfd)) { + /* pass the raw socket into the SSL layers */ failf(data, "SSL: SSL_set_fd failed: %s", ERR_error_string(ERR_get_error(), NULL)); return CURLE_SSL_CONNECT_ERROR; @@ -2102,12 +2199,14 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex) static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int err; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + long * const certverifyresult = SSL_IS_PROXY() ? + &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; DEBUGASSERT(ssl_connect_2 == connssl->connecting_state - || ssl_connect_2_reading == connssl->connecting_state - || ssl_connect_2_writing == connssl->connecting_state); + || ssl_connect_2_reading == connssl->connecting_state + || ssl_connect_2_writing == connssl->connecting_state); ERR_clear_error(); @@ -2154,6 +2253,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) lerr = SSL_get_verify_result(connssl->handle); if(lerr != X509_V_OK) { + *certverifyresult = lerr; snprintf(error_buffer, sizeof(error_buffer), "SSL certificate problem: %s", X509_verify_cert_error_string(lerr)); @@ -2165,7 +2265,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) } else { result = CURLE_SSL_CONNECT_ERROR; - SSL_strerror(errdetail, error_buffer, sizeof(error_buffer)); + ossl_strerror(errdetail, error_buffer, sizeof(error_buffer)); } /* detail is already set to the SSL error above */ @@ -2175,8 +2275,11 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) * the SO_ERROR is also lost. */ if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) { + const char * const hostname = SSL_IS_PROXY() ? + conn->http_proxy.host.name : conn->host.name; + const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; failf(data, "Unknown SSL protocol error in connection to %s:%ld ", - conn->host.name, conn->remote_port); + hostname, port); return result; } @@ -2200,7 +2303,7 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex) * negotiated */ if(conn->bits.tls_enable_alpn) { - const unsigned char* neg_protocol; + const unsigned char *neg_protocol; unsigned int len; SSL_get0_alpn_selected(connssl->handle, &neg_protocol, &len); if(len != 0) { @@ -2231,7 +2334,8 @@ static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len) { int i, ilen; - if((ilen = (int)len) < 0) + ilen = (int)len; + if(ilen < 0) return 1; /* buffer too big */ i = i2t_ASN1_OBJECT(buf, ilen, a); @@ -2250,11 +2354,14 @@ do { \ break; \ } WHILE_FALSE -static void pubkey_show(struct SessionHandle *data, +static void pubkey_show(struct Curl_easy *data, BIO *mem, int num, const char *type, const char *name, +#ifdef HAVE_OPAQUE_RSA_DSA_DH + const +#endif BIGNUM *bn) { char *ptr; @@ -2280,9 +2387,9 @@ do { \ } WHILE_FALSE #endif -static int X509V3_ext(struct SessionHandle *data, +static int X509V3_ext(struct Curl_easy *data, int certnum, - STACK_OF(X509_EXTENSION) *exts) + CONST_EXTS STACK_OF(X509_EXTENSION) *exts) { int i; size_t j; @@ -2340,7 +2447,7 @@ static CURLcode get_cert_chain(struct connectdata *conn, CURLcode result; STACK_OF(X509) *sk; int i; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; int numcerts; BIO *mem; @@ -2364,7 +2471,7 @@ static CURLcode get_cert_chain(struct connectdata *conn, EVP_PKEY *pubkey=NULL; int j; char *ptr; - ASN1_BIT_STRING *psig = NULL; + CONST_ASN1_BIT_STRING ASN1_BIT_STRING *psig = NULL; X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE); push_certinfo("Subject", i); @@ -2384,7 +2491,7 @@ static CURLcode get_cert_chain(struct connectdata *conn, #if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS) { - X509_ALGOR *palg = NULL; + const X509_ALGOR *palg = NULL; ASN1_STRING *a = ASN1_STRING_new(); if(a) { X509_get0_signature(&psig, &palg, x); @@ -2415,10 +2522,10 @@ static CURLcode get_cert_chain(struct connectdata *conn, } #endif - ASN1_TIME_print(mem, X509_get_notBefore(x)); + ASN1_TIME_print(mem, X509_get0_notBefore(x)); push_certinfo("Start date", i); - ASN1_TIME_print(mem, X509_get_notAfter(x)); + ASN1_TIME_print(mem, X509_get0_notAfter(x)); push_certinfo("Expire date", i); pubkey = X509_get_pubkey(x); @@ -2443,14 +2550,14 @@ static CURLcode get_cert_chain(struct connectdata *conn, #ifdef HAVE_OPAQUE_RSA_DSA_DH { - BIGNUM *n; - BIGNUM *e; - BIGNUM *d; - BIGNUM *p; - BIGNUM *q; - BIGNUM *dmp1; - BIGNUM *dmq1; - BIGNUM *iqmp; + const BIGNUM *n; + const BIGNUM *e; + const BIGNUM *d; + const BIGNUM *p; + const BIGNUM *q; + const BIGNUM *dmp1; + const BIGNUM *dmq1; + const BIGNUM *iqmp; RSA_get0_key(rsa, &n, &e, &d); RSA_get0_factors(rsa, &p, &q); @@ -2491,11 +2598,11 @@ static CURLcode get_cert_chain(struct connectdata *conn, #endif #ifdef HAVE_OPAQUE_RSA_DSA_DH { - BIGNUM *p; - BIGNUM *q; - BIGNUM *g; - BIGNUM *priv_key; - BIGNUM *pub_key; + const BIGNUM *p; + const BIGNUM *q; + const BIGNUM *g; + const BIGNUM *priv_key; + const BIGNUM *pub_key; DSA_get0_pqg(dsa, &p, &q, &g); DSA_get0_key(dsa, &pub_key, &priv_key); @@ -2525,11 +2632,11 @@ static CURLcode get_cert_chain(struct connectdata *conn, #endif #ifdef HAVE_OPAQUE_RSA_DSA_DH { - BIGNUM *p; - BIGNUM *q; - BIGNUM *g; - BIGNUM *priv_key; - BIGNUM *pub_key; + const BIGNUM *p; + const BIGNUM *q; + const BIGNUM *g; + const BIGNUM *priv_key; + const BIGNUM *pub_key; DH_get0_pqg(dh, &p, &q, &g); DH_get0_key(dh, &pub_key, &priv_key); print_pubkey_BN(dh, p, i); @@ -2574,7 +2681,7 @@ static CURLcode get_cert_chain(struct connectdata *conn, * Heavily modified from: * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL */ -static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data, X509* cert, +static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, const char *pinnedpubkey) { /* Scratch */ @@ -2602,7 +2709,7 @@ static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data, X509* cert, break; /* failed */ /* https://www.openssl.org/docs/crypto/buffer.html */ - buff1 = temp = OPENSSL_malloc(len1); + buff1 = temp = malloc(len1); if(!buff1) break; /* failed */ @@ -2625,7 +2732,7 @@ static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data, X509* cert, /* https://www.openssl.org/docs/crypto/buffer.html */ if(buff1) - OPENSSL_free(buff1); + free(buff1); return result; } @@ -2645,11 +2752,13 @@ static CURLcode servercert(struct connectdata *conn, CURLcode result = CURLE_OK; int rc; long lerr, len; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; X509 *issuer; FILE *fp; char *buffer = data->state.buffer; const char *ptr; + long * const certverifyresult = SSL_IS_PROXY() ? + &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult; BIO *mem = BIO_new(BIO_s_mem()); if(data->set.ssl.certinfo) @@ -2665,25 +2774,25 @@ static CURLcode servercert(struct connectdata *conn, return CURLE_PEER_FAILED_VERIFICATION; } - infof(data, "Server certificate:\n"); + infof(data, "%s certificate:\n", SSL_IS_PROXY() ? "Proxy" : "Server"); rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert), buffer, BUFSIZE); infof(data, " subject: %s\n", rc?"[NONE]":buffer); - ASN1_TIME_print(mem, X509_get_notBefore(connssl->server_cert)); + ASN1_TIME_print(mem, X509_get0_notBefore(connssl->server_cert)); len = BIO_get_mem_data(mem, (char **) &ptr); infof(data, " start date: %.*s\n", len, ptr); rc = BIO_reset(mem); - ASN1_TIME_print(mem, X509_get_notAfter(connssl->server_cert)); + ASN1_TIME_print(mem, X509_get0_notAfter(connssl->server_cert)); len = BIO_get_mem_data(mem, (char **) &ptr); infof(data, " expire date: %.*s\n", len, ptr); rc = BIO_reset(mem); BIO_free(mem); - if(data->set.ssl.verifyhost) { + if(SSL_CONN_CONFIG(verifyhost)) { result = verifyhost(conn, connssl->server_cert); if(result) { X509_free(connssl->server_cert); @@ -2706,12 +2815,12 @@ static CURLcode servercert(struct connectdata *conn, deallocating the certificate. */ /* e.g. match issuer name with provided issuer certificate */ - if(data->set.str[STRING_SSL_ISSUERCERT]) { - fp = fopen(data->set.str[STRING_SSL_ISSUERCERT], FOPEN_READTEXT); + if(SSL_SET_OPTION(issuercert)) { + fp = fopen(SSL_SET_OPTION(issuercert), FOPEN_READTEXT); if(!fp) { if(strict) failf(data, "SSL: Unable to open issuer cert (%s)", - data->set.str[STRING_SSL_ISSUERCERT]); + SSL_SET_OPTION(issuercert)); X509_free(connssl->server_cert); connssl->server_cert = NULL; return CURLE_SSL_ISSUER_ERROR; @@ -2721,7 +2830,7 @@ static CURLcode servercert(struct connectdata *conn, if(!issuer) { if(strict) failf(data, "SSL: Unable to read issuer cert (%s)", - data->set.str[STRING_SSL_ISSUERCERT]); + SSL_SET_OPTION(issuercert)); X509_free(connssl->server_cert); X509_free(issuer); fclose(fp); @@ -2733,7 +2842,7 @@ static CURLcode servercert(struct connectdata *conn, if(X509_check_issued(issuer, connssl->server_cert) != X509_V_OK) { if(strict) failf(data, "SSL: Certificate issuer check failed (%s)", - data->set.str[STRING_SSL_ISSUERCERT]); + SSL_SET_OPTION(issuercert)); X509_free(connssl->server_cert); X509_free(issuer); connssl->server_cert = NULL; @@ -2741,15 +2850,14 @@ static CURLcode servercert(struct connectdata *conn, } infof(data, " SSL certificate issuer check ok (%s)\n", - data->set.str[STRING_SSL_ISSUERCERT]); + SSL_SET_OPTION(issuercert)); X509_free(issuer); } - lerr = data->set.ssl.certverifyresult = - SSL_get_verify_result(connssl->handle); + lerr = *certverifyresult = SSL_get_verify_result(connssl->handle); - if(data->set.ssl.certverifyresult != X509_V_OK) { - if(data->set.ssl.verifypeer) { + if(*certverifyresult != X509_V_OK) { + if(SSL_CONN_CONFIG(verifypeer)) { /* We probably never reach this, because SSL_connect() will fail and we return earlier if verifypeer is set? */ if(strict) @@ -2768,7 +2876,7 @@ static CURLcode servercert(struct connectdata *conn, #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ !defined(OPENSSL_NO_OCSP) - if(data->set.ssl.verifystatus) { + if(SSL_CONN_CONFIG(verifystatus)) { result = verifystatus(conn, connssl); if(result) { X509_free(connssl->server_cert); @@ -2782,7 +2890,8 @@ static CURLcode servercert(struct connectdata *conn, /* when not strict, we don't bother about the verify cert problems */ result = CURLE_OK; - ptr = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : + data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; if(!result && ptr) { result = pkp_pin_peer_pubkey(data, connssl->server_cert, ptr); if(result) @@ -2799,43 +2908,50 @@ static CURLcode servercert(struct connectdata *conn, static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; - void *old_ssl_sessionid = NULL; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - bool incache; - SSL_SESSION *our_ssl_sessionid; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - our_ssl_sessionid = SSL_get1_session(connssl->handle); + if(data->set.general_ssl.sessionid) { + bool incache; + SSL_SESSION *our_ssl_sessionid; + void *old_ssl_sessionid = NULL; - /* SSL_get1_session() will increment the reference count and the session - will stay in memory until explicitly freed with SSL_SESSION_free(3), - regardless of its state. */ + our_ssl_sessionid = SSL_get1_session(connssl->handle); - incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)); - if(incache) { - if(old_ssl_sessionid != our_ssl_sessionid) { - infof(data, "old SSL session ID is stale, removing\n"); - Curl_ssl_delsessionid(conn, old_ssl_sessionid); - incache = FALSE; + /* SSL_get1_session() will increment the reference count and the session + will stay in memory until explicitly freed with SSL_SESSION_free(3), + regardless of its state. */ + + Curl_ssl_sessionid_lock(conn); + incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, + sockindex)); + if(incache) { + if(old_ssl_sessionid != our_ssl_sessionid) { + infof(data, "old SSL session ID is stale, removing\n"); + Curl_ssl_delsessionid(conn, old_ssl_sessionid); + incache = FALSE; + } } - } - if(!incache) { - result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */); - if(result) { - failf(data, "failed to store ssl session"); - return result; + if(!incache) { + result = Curl_ssl_addsessionid(conn, our_ssl_sessionid, + 0 /* unknown size */, sockindex); + if(result) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "failed to store ssl session"); + return result; + } } - } - else { - /* Session was incache, so refcount already incremented earlier. - * Avoid further increments with each SSL_get1_session() call. - * This does not free the session as refcount remains > 0 - */ - SSL_SESSION_free(our_ssl_sessionid); + else { + /* Session was incache, so refcount already incremented earlier. + * Avoid further increments with each SSL_get1_session() call. + * This does not free the session as refcount remains > 0 + */ + SSL_SESSION_free(our_ssl_sessionid); + } + Curl_ssl_sessionid_unlock(conn); } /* @@ -2845,8 +2961,8 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex) * operations. */ - result = servercert(conn, connssl, - (data->set.ssl.verifypeer || data->set.ssl.verifyhost)); + result = servercert(conn, connssl, (SSL_CONN_CONFIG(verifypeer) || + SSL_CONN_CONFIG(verifyhost))); if(!result) connssl->connecting_state = ssl_connect_done; @@ -2863,10 +2979,10 @@ static CURLcode ossl_connect_common(struct connectdata *conn, bool *done) { CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; - long timeout_ms; + time_t timeout_ms; int what; /* check if the connection has already been established */ @@ -2912,7 +3028,8 @@ static CURLcode ossl_connect_common(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -2993,7 +3110,10 @@ bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex) { if(conn->ssl[connindex].handle) /* SSL is in use */ - return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE; + return (0 != SSL_pending(conn->ssl[connindex].handle) || + (conn->proxy_ssl[connindex].handle && + 0 != SSL_pending(conn->proxy_ssl[connindex].handle))) ? + TRUE : FALSE; else return FALSE; } @@ -3007,7 +3127,7 @@ static ssize_t ossl_send(struct connectdata *conn, /* SSL_write() is said to return 'int' while write() and send() returns 'size_t' */ int err; - char error_buffer[120]; /* OpenSSL documents that this must be at least 120 + char error_buffer[256]; /* OpenSSL documents that this must be at least 256 bytes long. */ unsigned long sslerror; int memlen; @@ -3038,8 +3158,18 @@ static ssize_t ossl_send(struct connectdata *conn, /* A failure in the SSL library occurred, usually a protocol error. The OpenSSL error queue contains more information on the error. */ sslerror = ERR_get_error(); - failf(conn->data, "SSL_write() error: %s", - ERR_error_string(sslerror, error_buffer)); + if(ERR_GET_LIB(sslerror) == ERR_LIB_SSL && + ERR_GET_REASON(sslerror) == SSL_R_BIO_NOT_SET && + conn->ssl[sockindex].state == ssl_connection_complete && + conn->proxy_ssl[sockindex].state == ssl_connection_complete) { + char ver[120]; + Curl_ossl_version(ver, 120); + failf(conn->data, "Error: %s does not support double SSL tunneling.", + ver); + } + else + failf(conn->data, "SSL_write() error: %s", + ossl_strerror(sslerror, error_buffer, sizeof(error_buffer))); *curlcode = CURLE_SEND_ERROR; return -1; } @@ -3058,8 +3188,8 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ size_t buffersize, /* max amount to read */ CURLcode *curlcode) { - char error_buffer[120]; /* OpenSSL documents that this must be at - least 120 bytes long. */ + char error_buffer[256]; /* OpenSSL documents that this must be at + least 256 bytes long. */ unsigned long sslerror; ssize_t nread; int buffsize; @@ -3090,7 +3220,7 @@ static ssize_t ossl_recv(struct connectdata *conn, /* connection data */ /* If the return code was negative or there actually is an error in the queue */ failf(conn->data, "SSL read: %s, errno %d", - ERR_error_string(sslerror, error_buffer), + ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)), SOCKERRNO); *curlcode = CURLE_RECV_ERROR; return -1; @@ -3109,7 +3239,7 @@ size_t Curl_ossl_version(char *buffer, size_t size) unsigned long ssleay_value; sub[2]='\0'; sub[1]='\0'; - ssleay_value=SSLeay(); + ssleay_value=OpenSSL_version_num(); if(ssleay_value < 0x906000) { ssleay_value=SSLEAY_VERSION_NUMBER; sub[0]='\0'; @@ -3123,7 +3253,7 @@ size_t Curl_ossl_version(char *buffer, size_t size) sub[0] = 'z'; } else { - sub[0]=(char)(((ssleay_value>>4)&0xff) + 'a' -1); + sub[0] = (char) (minor_ver + 'a' - 1); } } else @@ -3140,14 +3270,21 @@ size_t Curl_ossl_version(char *buffer, size_t size) } /* can be called with data == NULL */ -int Curl_ossl_random(struct SessionHandle *data, unsigned char *entropy, - size_t length) +CURLcode Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy, + size_t length) { + int rc; if(data) { - Curl_ossl_seed(data); /* Initiate the seed if not already done */ + if(Curl_ossl_seed(data)) /* Initiate the seed if not already done */ + return CURLE_FAILED_INIT; /* couldn't seed for some reason */ } - RAND_bytes(entropy, curlx_uztosi(length)); - return 0; /* 0 as in no problem */ + else { + if(!rand_enough()) + return CURLE_FAILED_INIT; + } + /* RAND_bytes() returns 1 on success, 0 otherwise. */ + rc = RAND_bytes(entropy, curlx_uztosi(length)); + return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT); } void Curl_ossl_md5sum(unsigned char *tmp, /* input */ diff --git a/contrib/curl/lib/vtls/openssl.h b/contrib/curl/lib/vtls/openssl.h index 74f128ed..b9648d51 100644 --- a/contrib/curl/lib/vtls/openssl.h +++ b/contrib/curl/lib/vtls/openssl.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -41,20 +41,20 @@ void Curl_ossl_close(struct connectdata *conn, int sockindex); /* tell OpenSSL to close down all open information regarding connections (and thus session ID caching etc) */ -void Curl_ossl_close_all(struct SessionHandle *data); +void Curl_ossl_close_all(struct Curl_easy *data); /* Sets an OpenSSL engine */ -CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine); +CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine); /* function provided for the generic SSL-layer, called when a session id should be freed */ void Curl_ossl_session_free(void *ptr); /* Sets engine as default for all SSL operations */ -CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data); +CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data); /* Build list of OpenSSL engines */ -struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data); +struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data); int Curl_ossl_init(void); void Curl_ossl_cleanup(void); @@ -66,8 +66,8 @@ bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex); /* return 0 if a find random is filled in */ -int Curl_ossl_random(struct SessionHandle *data, unsigned char *entropy, - size_t length); +CURLcode Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy, + size_t length); void Curl_ossl_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum /* output */, @@ -79,6 +79,9 @@ void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */ bool Curl_ossl_cert_status_request(void); +/* Support HTTPS-proxy */ +#define HTTPS_PROXY_SUPPORT 1 + /* Set the API backend definition to OpenSSL */ #define CURL_SSL_BACKEND CURLSSLBACKEND_OPENSSL diff --git a/contrib/curl/lib/vtls/polarssl.c b/contrib/curl/lib/vtls/polarssl.c index 0e8b0f50..e5346ce3 100644 --- a/contrib/curl/lib/vtls/polarssl.c +++ b/contrib/curl/lib/vtls/polarssl.c @@ -54,7 +54,7 @@ #include "parsedate.h" #include "connect.h" /* for the connect timeout */ #include "select.h" -#include "rawstr.h" +#include "strcase.h" #include "polarssl_threadlock.h" #include "curl_printf.h" #include "curl_memory.h" @@ -75,6 +75,11 @@ #define THREADING_SUPPORT #endif +#ifndef POLARSSL_ERROR_C +#define error_strerror(x,y,z) +#endif /* POLARSSL_ERROR_C */ + + #if defined(THREADING_SUPPORT) static entropy_context entropy; @@ -96,13 +101,13 @@ static void entropy_init_mutex(entropy_context *ctx) /* start of entropy_func_mutex() */ static int entropy_func_mutex(void *data, unsigned char *output, size_t len) { - int ret; - /* lock 1 = entropy_func_mutex() */ - Curl_polarsslthreadlock_lock_function(1); - ret = entropy_func(data, output, len); - Curl_polarsslthreadlock_unlock_function(1); + int ret; + /* lock 1 = entropy_func_mutex() */ + Curl_polarsslthreadlock_lock_function(1); + ret = entropy_func(data, output, len); + Curl_polarsslthreadlock_unlock_function(1); - return ret; + return ret; } /* end of entropy_func_mutex() */ @@ -114,12 +119,12 @@ static int entropy_func_mutex(void *data, unsigned char *output, size_t len) #ifdef POLARSSL_DEBUG static void polarssl_debug(void *context, int level, const char *line) { - struct SessionHandle *data = NULL; + struct Curl_easy *data = NULL; if(!context) return; - data = (struct SessionHandle *)context; + data = (struct Curl_easy *)context; infof(data, "%s", line); (void) level; @@ -138,85 +143,70 @@ static Curl_send polarssl_send; static CURLcode polarssl_connect_step1(struct connectdata *conn, - int sockindex) + int sockindex) { - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; - - bool sni = TRUE; /* default is SNI enabled */ + const char *capath = SSL_CONN_CONFIG(CApath); + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; + const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port; int ret = -1; -#ifdef ENABLE_IPV6 - struct in6_addr addr; -#else - struct in_addr addr; -#endif - void *old_session = NULL; char errorbuf[128]; errorbuf[0]=0; /* PolarSSL only supports SSLv3 and TLSv1 */ - if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) { + if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) { failf(data, "PolarSSL does not support SSLv2"); return CURLE_SSL_CONNECT_ERROR; } - else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) - sni = FALSE; /* SSLv3 has no SNI */ #ifdef THREADING_SUPPORT entropy_init_mutex(&entropy); if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func_mutex, &entropy, NULL, 0)) != 0) { -#ifdef POLARSSL_ERROR_C - error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ - failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", - -ret, errorbuf); + error_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", + -ret, errorbuf); } #else entropy_init(&connssl->entropy); if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func, &connssl->entropy, NULL, 0)) != 0) { -#ifdef POLARSSL_ERROR_C - error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ - failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", - -ret, errorbuf); + error_strerror(ret, errorbuf, sizeof(errorbuf)); + failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n", + -ret, errorbuf); } #endif /* THREADING_SUPPORT */ /* Load the trusted CA */ memset(&connssl->cacert, 0, sizeof(x509_crt)); - if(data->set.str[STRING_SSL_CAFILE]) { + if(SSL_CONN_CONFIG(CAfile)) { ret = x509_crt_parse_file(&connssl->cacert, - data->set.str[STRING_SSL_CAFILE]); + SSL_CONN_CONFIG(CAfile)); if(ret<0) { -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "Error reading ca cert file %s - PolarSSL: (-0x%04X) %s", - data->set.str[STRING_SSL_CAFILE], -ret, errorbuf); + SSL_CONN_CONFIG(CAfile), -ret, errorbuf); - if(data->set.ssl.verifypeer) + if(SSL_CONN_CONFIG(verifypeer)) return CURLE_SSL_CACERT_BADFILE; } } - if(data->set.str[STRING_SSL_CAPATH]) { - ret = x509_crt_parse_path(&connssl->cacert, - data->set.str[STRING_SSL_CAPATH]); + if(capath) { + ret = x509_crt_parse_path(&connssl->cacert, capath); if(ret<0) { -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "Error reading ca cert path %s - PolarSSL: (-0x%04X) %s", - data->set.str[STRING_SSL_CAPATH], -ret, errorbuf); + capath, -ret, errorbuf); - if(data->set.ssl.verifypeer) + if(SSL_CONN_CONFIG(verifypeer)) return CURLE_SSL_CACERT_BADFILE; } } @@ -224,27 +214,25 @@ polarssl_connect_step1(struct connectdata *conn, /* Load the client certificate */ memset(&connssl->clicert, 0, sizeof(x509_crt)); - if(data->set.str[STRING_CERT]) { + if(SSL_SET_OPTION(cert)) { ret = x509_crt_parse_file(&connssl->clicert, - data->set.str[STRING_CERT]); + SSL_SET_OPTION(cert)); if(ret) { -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "Error reading client cert file %s - PolarSSL: (-0x%04X) %s", - data->set.str[STRING_CERT], -ret, errorbuf); + SSL_SET_OPTION(cert), -ret, errorbuf); return CURLE_SSL_CERTPROBLEM; } } /* Load the client private key */ - if(data->set.str[STRING_KEY]) { + if(SSL_SET_OPTION(key)) { pk_context pk; pk_init(&pk); - ret = pk_parse_keyfile(&pk, data->set.str[STRING_KEY], - data->set.str[STRING_KEY_PASSWD]); + ret = pk_parse_keyfile(&pk, SSL_SET_OPTION(key), + SSL_SET_OPTION(key_passwd)); if(ret == 0 && !pk_can_do(&pk, POLARSSL_PK_RSA)) ret = POLARSSL_ERR_PK_TYPE_MISMATCH; if(ret == 0) @@ -254,11 +242,9 @@ polarssl_connect_step1(struct connectdata *conn, pk_free(&pk); if(ret) { -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "Error reading private key %s - PolarSSL: (-0x%04X) %s", - data->set.str[STRING_KEY], -ret, errorbuf); + SSL_SET_OPTION(key), -ret, errorbuf); return CURLE_SSL_CERTPROBLEM; } @@ -267,31 +253,27 @@ polarssl_connect_step1(struct connectdata *conn, /* Load the CRL */ memset(&connssl->crl, 0, sizeof(x509_crl)); - if(data->set.str[STRING_SSL_CRLFILE]) { + if(SSL_SET_OPTION(CRLfile)) { ret = x509_crl_parse_file(&connssl->crl, - data->set.str[STRING_SSL_CRLFILE]); + SSL_SET_OPTION(CRLfile)); if(ret) { -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "Error reading CRL file %s - PolarSSL: (-0x%04X) %s", - data->set.str[STRING_SSL_CRLFILE], -ret, errorbuf); + SSL_SET_OPTION(CRLfile), -ret, errorbuf); return CURLE_SSL_CRL_BADFILE; } } - infof(data, "PolarSSL: Connecting to %s:%d\n", - conn->host.name, conn->remote_port); + infof(data, "PolarSSL: Connecting to %s:%d\n", hostname, port); if(ssl_init(&connssl->ssl)) { failf(data, "PolarSSL: ssl_init failed"); return CURLE_SSL_CONNECT_ERROR; } - switch(data->set.ssl.version) { - default: + switch(SSL_CONN_CONFIG(version)) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, @@ -325,6 +307,12 @@ polarssl_connect_step1(struct connectdata *conn, SSL_MINOR_VERSION_3); infof(data, "PolarSSL: Forced min. SSL Version to be TLS 1.2\n"); break; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "PolarSSL: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; } ssl_set_endpoint(&connssl->ssl, SSL_IS_CLIENT); @@ -337,24 +325,33 @@ polarssl_connect_step1(struct connectdata *conn, net_send, &conn->sock[sockindex]); ssl_set_ciphersuites(&connssl->ssl, ssl_list_ciphersuites()); - if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) { - ret = ssl_set_session(&connssl->ssl, old_session); - if(ret) { - failf(data, "ssl_set_session returned -0x%x", -ret); - return CURLE_SSL_CONNECT_ERROR; + + /* Check if there's a cached ID we can/should use here! */ + if(data->set.general_ssl.sessionid) { + void *old_session = NULL; + + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) { + ret = ssl_set_session(&connssl->ssl, old_session); + if(ret) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "ssl_set_session returned -0x%x", -ret); + return CURLE_SSL_CONNECT_ERROR; + } + infof(data, "PolarSSL re-using session\n"); } - infof(data, "PolarSSL re-using session\n"); + Curl_ssl_sessionid_unlock(conn); } ssl_set_ca_chain(&connssl->ssl, &connssl->cacert, &connssl->crl, - conn->host.name); + hostname); ssl_set_own_cert_rsa(&connssl->ssl, &connssl->clicert, &connssl->rsa); - if(ssl_set_hostname(&connssl->ssl, conn->host.name)) { + if(ssl_set_hostname(&connssl->ssl, hostname)) { /* ssl_set_hostname() sets the name to use in CN/SAN checks *and* the name to set in the SNI extension. So even if curl connects to a host specified as an IP address, this function must be used. */ @@ -364,7 +361,7 @@ polarssl_connect_step1(struct connectdata *conn, #ifdef HAS_ALPN if(conn->bits.tls_enable_alpn) { - static const char* protocols[3]; + static const char *protocols[3]; int cur = 0; #ifdef USE_NGHTTP2 @@ -394,12 +391,16 @@ polarssl_connect_step1(struct connectdata *conn, static CURLcode polarssl_connect_step2(struct connectdata *conn, - int sockindex) + int sockindex) { int ret; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data* connssl = &conn->ssl[sockindex]; char buffer[1024]; + const char * const pinnedpubkey = SSL_IS_PROXY() ? + data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] : + data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]; + char errorbuf[128]; errorbuf[0] = 0; @@ -422,9 +423,7 @@ polarssl_connect_step2(struct connectdata *conn, return CURLE_OK; default: -#ifdef POLARSSL_ERROR_C error_strerror(ret, errorbuf, sizeof(errorbuf)); -#endif /* POLARSSL_ERROR_C */ failf(data, "ssl_handshake returned - PolarSSL: (-0x%04X) %s", -ret, errorbuf); return CURLE_SSL_CONNECT_ERROR; @@ -435,7 +434,7 @@ polarssl_connect_step2(struct connectdata *conn, ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl); - if(ret && data->set.ssl.verifypeer) { + if(ret && SSL_CONN_CONFIG(verifypeer)) { if(ret & BADCERT_EXPIRED) failf(data, "Cert verify failed: BADCERT_EXPIRED"); @@ -463,7 +462,7 @@ polarssl_connect_step2(struct connectdata *conn, } /* adapted from mbedtls.c */ - if(data->set.str[STRING_SSL_PINNEDPUBLICKEY]) { + if(pinnedpubkey) { int size; CURLcode result; x509_crt *p; @@ -505,7 +504,7 @@ polarssl_connect_step2(struct connectdata *conn, /* pk_write_pubkey_der writes data at the end of the buffer. */ result = Curl_pin_peer_pubkey(data, - data->set.str[STRING_SSL_PINNEDPUBLICKEY], + pinnedpubkey, &pubkey[PUB_DER_MAX_BYTES - size], size); if(result) { x509_crt_free(p); @@ -531,9 +530,9 @@ polarssl_connect_step2(struct connectdata *conn, } else #endif - if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) { - conn->negnpn = CURL_HTTP_VERSION_1_1; - } + if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) { + conn->negnpn = CURL_HTTP_VERSION_1_1; + } } else infof(data, "ALPN, server did not agree to a protocol\n"); @@ -548,38 +547,43 @@ polarssl_connect_step2(struct connectdata *conn, static CURLcode polarssl_connect_step3(struct connectdata *conn, - int sockindex) + int sockindex) { CURLcode retcode = CURLE_OK; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct SessionHandle *data = conn->data; - void *old_ssl_sessionid = NULL; - ssl_session *our_ssl_sessionid; - int ret; + struct Curl_easy *data = conn->data; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - our_ssl_sessionid = malloc(sizeof(ssl_session)); - if(!our_ssl_sessionid) - return CURLE_OUT_OF_MEMORY; + if(data->set.general_ssl.sessionid) { + int ret; + ssl_session *our_ssl_sessionid; + void *old_ssl_sessionid = NULL; - ssl_session_init(our_ssl_sessionid); + our_ssl_sessionid = malloc(sizeof(ssl_session)); + if(!our_ssl_sessionid) + return CURLE_OUT_OF_MEMORY; - ret = ssl_get_session(&connssl->ssl, our_ssl_sessionid); - if(ret) { - failf(data, "ssl_get_session returned -0x%x", -ret); - return CURLE_SSL_CONNECT_ERROR; - } + ssl_session_init(our_ssl_sessionid); - /* If there's already a matching session in the cache, delete it */ - if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL)) - Curl_ssl_delsessionid(conn, old_ssl_sessionid); + ret = ssl_get_session(&connssl->ssl, our_ssl_sessionid); + if(ret) { + failf(data, "ssl_get_session returned -0x%x", -ret); + return CURLE_SSL_CONNECT_ERROR; + } - retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0); - if(retcode) { - free(our_ssl_sessionid); - failf(data, "failed to store ssl session"); - return retcode; + /* If there's already a matching session in the cache, delete it */ + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex)) + Curl_ssl_delsessionid(conn, old_ssl_sessionid); + + retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex); + Curl_ssl_sessionid_unlock(conn); + if(retcode) { + free(our_ssl_sessionid); + failf(data, "failed to store ssl session"); + return retcode; + } } connssl->connecting_state = ssl_connect_done; @@ -666,7 +670,7 @@ polarssl_connect_common(struct connectdata *conn, bool *done) { CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; long timeout_ms; @@ -715,7 +719,8 @@ polarssl_connect_common(struct connectdata *conn, curl_socket_t readfd = ssl_connect_2_reading== connssl->connecting_state?sockfd:CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking?0:timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -774,8 +779,8 @@ polarssl_connect_common(struct connectdata *conn, CURLcode Curl_polarssl_connect_nonblocking(struct connectdata *conn, - int sockindex, - bool *done) + int sockindex, + bool *done) { return polarssl_connect_common(conn, sockindex, TRUE, done); } @@ -783,7 +788,7 @@ Curl_polarssl_connect_nonblocking(struct connectdata *conn, CURLcode Curl_polarssl_connect(struct connectdata *conn, - int sockindex) + int sockindex) { CURLcode result; bool done = FALSE; @@ -811,4 +816,10 @@ void Curl_polarssl_cleanup(void) (void)Curl_polarsslthreadlock_thread_cleanup(); } + +int Curl_polarssl_data_pending(const struct connectdata *conn, int sockindex) +{ + return ssl_get_bytes_avail(&conn->ssl[sockindex].ssl) != 0; +} + #endif /* USE_POLARSSL */ diff --git a/contrib/curl/lib/vtls/polarssl.h b/contrib/curl/lib/vtls/polarssl.h index 7098b24a..47af7b41 100644 --- a/contrib/curl/lib/vtls/polarssl.h +++ b/contrib/curl/lib/vtls/polarssl.h @@ -31,6 +31,7 @@ /* Called on first use PolarSSL, setup threading if supported */ int Curl_polarssl_init(void); void Curl_polarssl_cleanup(void); +int Curl_polarssl_data_pending(const struct connectdata *conn, int sockindex); CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex); @@ -69,7 +70,7 @@ int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex); #define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL) #define curlssl_version Curl_polarssl_version #define curlssl_check_cxn(x) ((void)x, -1) -#define curlssl_data_pending(x,y) ((void)x, (void)y, 0) +#define curlssl_data_pending(x,y) Curl_polarssl_data_pending(x, y) #define curlssl_sha256sum(a,b,c,d) sha256(a,b,c,0) /* This might cause libcurl to use a weeker random! diff --git a/contrib/curl/lib/vtls/polarssl_threadlock.c b/contrib/curl/lib/vtls/polarssl_threadlock.c index 3b0ebf88..b1eb7b74 100644 --- a/contrib/curl/lib/vtls/polarssl_threadlock.c +++ b/contrib/curl/lib/vtls/polarssl_threadlock.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2013-2015, Daniel Stenberg, , et al. + * Copyright (C) 2013-2016, Daniel Stenberg, , et al. * Copyright (C) 2010, 2011, Hoi-Ho Chan, * * This software is licensed as described in the file COPYING, which @@ -52,7 +52,7 @@ int Curl_polarsslthreadlock_thread_setup(void) int i; int ret; - mutex_buf = malloc(NUMT * sizeof(POLARSSL_MUTEX_T)); + mutex_buf = calloc(NUMT * sizeof(POLARSSL_MUTEX_T), 1); if(!mutex_buf) return 0; /* error, no number of threads defined */ diff --git a/contrib/curl/lib/vtls/schannel.c b/contrib/curl/lib/vtls/schannel.c index b2e92656..bd923995 100644 --- a/contrib/curl/lib/vtls/schannel.c +++ b/contrib/curl/lib/vtls/schannel.c @@ -7,7 +7,7 @@ * * Copyright (C) 2012 - 2016, Marc Hoersken, * Copyright (C) 2012, Mark Salisbury, - * Copyright (C) 2012 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -56,13 +56,20 @@ #include "inet_pton.h" /* for IP addr SNI check */ #include "curl_multibyte.h" #include "warnless.h" +#include "x509asn1.h" #include "curl_printf.h" +#include "system_win32.h" +#include "hostcheck.h" + + /* The last #include file should be: */ #include "curl_memory.h" -/* The last #include file should be: */ #include "memdebug.h" -/* ALPN requires version 8.1 of the Windows SDK, which was - shipped with Visual Studio 2013, aka _MSC_VER 1800*/ +/* ALPN requires version 8.1 of the Windows SDK, which was + shipped with Visual Studio 2013, aka _MSC_VER 1800: + + https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx +*/ #if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_) # define HAS_ALPN 1 #endif @@ -99,7 +106,7 @@ static CURLcode schannel_connect_step1(struct connectdata *conn, int sockindex) { ssize_t written = -1; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; SecBuffer outbuf; SecBufferDesc outbuf_desc; @@ -117,21 +124,55 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) #endif TCHAR *host_name; CURLcode result; + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n", - conn->host.name, conn->remote_port); + hostname, conn->remote_port); + + if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT, + VERSION_LESS_THAN_EQUAL)) { + /* SChannel in Windows XP (OS version 5.1) uses legacy handshakes and + algorithms that may not be supported by all servers. */ + infof(data, "schannel: WinSSL version is old and may not be able to " + "connect to some servers due to lack of SNI, algorithms, etc.\n"); + } + +#ifdef HAS_ALPN + /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above. + Also it doesn't seem to be supported for Wine, see curl bug #983. */ + connssl->use_alpn = conn->bits.tls_enable_alpn && + !GetProcAddress(GetModuleHandleA("ntdll"), + "wine_get_version") && + Curl_verify_windows_version(6, 3, PLATFORM_WINNT, + VERSION_GREATER_THAN_EQUAL); +#else + connssl->use_alpn = false; +#endif + + connssl->cred = NULL; /* check for an existing re-usable credential handle */ - if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)) { - connssl->cred = old_cred; - infof(data, "schannel: re-using existing credential handle\n"); + if(data->set.general_ssl.sessionid) { + Curl_ssl_sessionid_lock(conn); + if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) { + connssl->cred = old_cred; + infof(data, "schannel: re-using existing credential handle\n"); + + /* increment the reference counter of the credential/session handle */ + connssl->cred->refcount++; + infof(data, "schannel: incremented credential handle refcount = %d\n", + connssl->cred->refcount); + } + Curl_ssl_sessionid_unlock(conn); } - else { + + if(!connssl->cred) { /* setup Schannel API options */ memset(&schannel_cred, 0, sizeof(schannel_cred)); schannel_cred.dwVersion = SCHANNEL_CRED_VERSION; - if(data->set.ssl.verifypeer) { + if(conn->ssl_config.verifypeer) { #ifdef _WIN32_WCE /* certificate validation on CE doesn't seem to work right; we'll do it following a more manual process. */ @@ -140,13 +181,14 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) SCH_CRED_IGNORE_REVOCATION_OFFLINE; #else schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION; - if(data->set.ssl_no_revoke) + /* TODO s/data->set.ssl.no_revoke/SSL_SET_OPTION(no_revoke)/g */ + if(data->set.ssl.no_revoke) schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK | SCH_CRED_IGNORE_REVOCATION_OFFLINE; else schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN; #endif - if(data->set.ssl_no_revoke) + if(data->set.ssl.no_revoke) infof(data, "schannel: disabled server certificate revocation " "checks\n"); else @@ -159,15 +201,14 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) infof(data, "schannel: disabled server certificate revocation checks\n"); } - if(!data->set.ssl.verifyhost) { + if(!conn->ssl_config.verifyhost) { schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK; infof(data, "schannel: verifyhost setting prevents Schannel from " "comparing the supplied target name with the subject " - "names in server certificates. Also disables SNI.\n"); + "names in server certificates.\n"); } - switch(data->set.ssl.version) { - default: + switch(conn->ssl_config.version) { case CURL_SSLVERSION_DEFAULT: case CURL_SSLVERSION_TLSv1: schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT | @@ -183,12 +224,18 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) case CURL_SSLVERSION_TLSv1_2: schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT; break; + case CURL_SSLVERSION_TLSv1_3: + failf(data, "Schannel: TLS 1.3 is not yet supported"); + return CURLE_SSL_CONNECT_ERROR; case CURL_SSLVERSION_SSLv3: schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT; break; case CURL_SSLVERSION_SSLv2: schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT; break; + default: + failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION"); + return CURLE_SSL_CONNECT_ERROR; } /* allocate memory for the re-usable credential handle */ @@ -199,6 +246,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) return CURLE_OUT_OF_MEMORY; } memset(connssl->cred, 0, sizeof(struct curl_schannel_cred)); + connssl->cred->refcount = 1; /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */ @@ -222,29 +270,29 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) } /* Warn if SNI is disabled due to use of an IP address */ - if(Curl_inet_pton(AF_INET, conn->host.name, &addr) + if(Curl_inet_pton(AF_INET, hostname, &addr) #ifdef ENABLE_IPV6 - || Curl_inet_pton(AF_INET6, conn->host.name, &addr6) + || Curl_inet_pton(AF_INET6, hostname, &addr6) #endif ) { infof(data, "schannel: using IP address, SNI is not supported by OS.\n"); } #ifdef HAS_ALPN - if(conn->bits.tls_enable_alpn) { + if(connssl->use_alpn) { int cur = 0; int list_start_index = 0; - unsigned int* extension_len = NULL; + unsigned int *extension_len = NULL; unsigned short* list_len = NULL; /* The first four bytes will be an unsigned int indicating number of bytes of data in the rest of the the buffer. */ - extension_len = (unsigned int*)(&alpn_buffer[cur]); + extension_len = (unsigned int *)(&alpn_buffer[cur]); cur += sizeof(unsigned int); /* The next four bytes are an indicator that this buffer will contain ALPN data, as opposed to NPN, for example. */ - *(unsigned int*)&alpn_buffer[cur] = + *(unsigned int *)&alpn_buffer[cur] = SecApplicationProtocolNegotiationExt_ALPN; cur += sizeof(unsigned int); @@ -302,15 +350,21 @@ schannel_connect_step1(struct connectdata *conn, int sockindex) } memset(connssl->ctxt, 0, sizeof(struct curl_schannel_ctxt)); - host_name = Curl_convert_UTF8_to_tchar(conn->host.name); + host_name = Curl_convert_UTF8_to_tchar(hostname); if(!host_name) return CURLE_OUT_OF_MEMORY; - /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */ + /* Schannel InitializeSecurityContext: + https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx + At the moment we don't pass inbuf unless we're using ALPN since we only + use it for that, and Wine (for which we currently disable ALPN) is giving + us problems with inbuf regardless. https://github.com/curl/curl/issues/983 + */ sspi_status = s_pSecFn->InitializeSecurityContext( - &connssl->cred->cred_handle, NULL, host_name, - connssl->req_flags, 0, 0, &inbuf_desc, 0, &connssl->ctxt->ctxt_handle, + &connssl->cred->cred_handle, NULL, host_name, connssl->req_flags, 0, 0, + (connssl->use_alpn ? &inbuf_desc : NULL), + 0, &connssl->ctxt->ctxt_handle, &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp); Curl_unicodefree(host_name); @@ -357,7 +411,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) { int i; ssize_t nread = -1, written = -1; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; unsigned char *reallocated_buffer; size_t reallocated_length; @@ -369,11 +423,13 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) TCHAR *host_name; CURLcode result; bool doread; + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE; infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n", - conn->host.name, conn->remote_port); + hostname, conn->remote_port); if(!connssl->cred || !connssl->ctxt) return CURLE_SSL_CONNECT_ERROR; @@ -469,7 +525,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer, connssl->encdata_offset); - host_name = Curl_convert_UTF8_to_tchar(conn->host.name); + host_name = Curl_convert_UTF8_to_tchar(hostname); if(!host_name) return CURLE_OUT_OF_MEMORY; @@ -586,7 +642,7 @@ schannel_connect_step2(struct connectdata *conn, int sockindex) #ifdef _WIN32_WCE /* Windows CE doesn't do any server certificate validation. We have to do it manually. */ - if(data->set.ssl.verifypeer) + if(conn->ssl_config.verifypeer) return verify_certificate(conn, sockindex); #endif @@ -597,19 +653,20 @@ static CURLcode schannel_connect_step3(struct connectdata *conn, int sockindex) { CURLcode result = CURLE_OK; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - struct curl_schannel_cred *old_cred = NULL; -#ifdef HAS_ALPN SECURITY_STATUS sspi_status = SEC_E_OK; + CERT_CONTEXT *ccert_context = NULL; + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; +#ifdef HAS_ALPN SecPkgContext_ApplicationProtocol alpn_result; #endif - bool incache; DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n", - conn->host.name, conn->remote_port); + hostname, conn->remote_port); if(!connssl->cred) return CURLE_SSL_CONNECT_ERROR; @@ -630,7 +687,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) } #ifdef HAS_ALPN - if(conn->bits.tls_enable_alpn) { + if(connssl->use_alpn) { sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result); @@ -664,34 +721,62 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) } #endif - /* increment the reference counter of the credential/session handle */ - if(connssl->cred && connssl->ctxt) { - connssl->cred->refcount++; - infof(data, "schannel: incremented credential handle refcount = %d\n", - connssl->cred->refcount); - } - /* save the current session data for possible re-use */ - incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)); - if(incache) { - if(old_cred != connssl->cred) { - infof(data, "schannel: old credential handle is stale, removing\n"); - Curl_ssl_delsessionid(conn, (void *)old_cred); - incache = FALSE; + if(data->set.general_ssl.sessionid) { + bool incache; + struct curl_schannel_cred *old_cred = NULL; + + Curl_ssl_sessionid_lock(conn); + incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, + sockindex)); + if(incache) { + if(old_cred != connssl->cred) { + infof(data, "schannel: old credential handle is stale, removing\n"); + /* we're not taking old_cred ownership here, no refcount++ is needed */ + Curl_ssl_delsessionid(conn, (void *)old_cred); + incache = FALSE; + } } + if(!incache) { + result = Curl_ssl_addsessionid(conn, (void *)connssl->cred, + sizeof(struct curl_schannel_cred), + sockindex); + if(result) { + Curl_ssl_sessionid_unlock(conn); + failf(data, "schannel: failed to store credential handle"); + return result; + } + else { + /* this cred session is now also referenced by sessionid cache */ + connssl->cred->refcount++; + infof(data, "schannel: stored credential handle in session cache\n"); + } + } + Curl_ssl_sessionid_unlock(conn); } - if(!incache) { - result = Curl_ssl_addsessionid(conn, (void *)connssl->cred, - sizeof(struct curl_schannel_cred)); - if(result) { - failf(data, "schannel: failed to store credential handle"); + if(data->set.ssl.certinfo) { + sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, + SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context); + + if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) { + failf(data, "schannel: failed to retrieve remote cert context"); + return CURLE_SSL_CONNECT_ERROR; + } + + result = Curl_ssl_init_certinfo(data, 1); + if(!result) { + if(((ccert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) && + (ccert_context->cbCertEncoded > 0)) { + + const char *beg = (const char *) ccert_context->pbCertEncoded; + const char *end = beg + ccert_context->cbCertEncoded; + result = Curl_extract_certinfo(conn, 0, beg, end); + } + } + CertFreeCertificateContext(ccert_context); + if(result) return result; - } - else { - connssl->cred->cached = TRUE; - infof(data, "schannel: stored credential handle in session cache\n"); - } } connssl->connecting_state = ssl_connect_done; @@ -704,10 +789,10 @@ schannel_connect_common(struct connectdata *conn, int sockindex, bool nonblocking, bool *done) { CURLcode result; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; curl_socket_t sockfd = conn->sock[sockindex]; - long timeout_ms; + time_t timeout_ms; int what; /* check if the connection has already been established */ @@ -753,7 +838,8 @@ schannel_connect_common(struct connectdata *conn, int sockindex, curl_socket_t readfd = ssl_connect_2_reading == connssl->connecting_state ? sockfd : CURL_SOCKET_BAD; - what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms); + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, + nonblocking ? 0 : timeout_ms); if(what < 0) { /* fatal error */ failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO); @@ -894,7 +980,7 @@ schannel_send(struct connectdata *conn, int sockindex, /* send entire message or fail */ while(len > (size_t)written) { ssize_t this_write; - long timeleft; + time_t timeleft; int what; this_write = 0; @@ -909,8 +995,7 @@ schannel_send(struct connectdata *conn, int sockindex, break; } - what = Curl_socket_ready(CURL_SOCKET_BAD, conn->sock[sockindex], - timeleft); + what = SOCKET_WRITABLE(conn->sock[sockindex], timeleft); if(what < 0) { /* fatal error */ failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO); @@ -963,7 +1048,7 @@ schannel_recv(struct connectdata *conn, int sockindex, { size_t size = 0; ssize_t nread = -1; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; unsigned char *reallocated_buffer; size_t reallocated_length; @@ -1226,39 +1311,8 @@ cleanup: */ if(len && !connssl->decdata_offset && connssl->recv_connection_closed && !connssl->recv_sspi_close_notify) { - bool isWin2k = FALSE; - -#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \ - (_WIN32_WINNT < _WIN32_WINNT_WIN2K) - OSVERSIONINFO osver; - - memset(&osver, 0, sizeof(osver)); - osver.dwOSVersionInfoSize = sizeof(osver); - - /* Find out the Windows version */ - if(GetVersionEx(&osver)) { - /* Verify the version number is 5.0 */ - if(osver.dwMajorVersion == 5 && osver.dwMinorVersion == 0) - isWin2k = TRUE; - } -#else - ULONGLONG cm; - OSVERSIONINFOEX osver; - - memset(&osver, 0, sizeof(osver)); - osver.dwOSVersionInfoSize = sizeof(osver); - osver.dwMajorVersion = 5; - - cm = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL); - cm = VerSetConditionMask(cm, VER_MINORVERSION, VER_EQUAL); - cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); - cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, VER_GREATER_EQUAL); - - if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION | - VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR), - cm)) - isWin2k = TRUE; -#endif + bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT, + VERSION_EQUAL); if(isWin2k && sspi_status == SEC_E_OK) connssl->recv_sspi_close_notify = true; @@ -1343,11 +1397,13 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx * Shutting Down an Schannel Connection */ - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name : + conn->host.name; infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n", - conn->host.name, conn->remote_port); + hostname, conn->remote_port); if(connssl->cred && connssl->ctxt) { SecBufferDesc BuffDesc; @@ -1369,7 +1425,7 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) failf(data, "schannel: ApplyControlToken failure: %s", Curl_sspi_strerror(conn, sspi_status)); - host_name = Curl_convert_UTF8_to_tchar(conn->host.name); + host_name = Curl_convert_UTF8_to_tchar(hostname); if(!host_name) return CURLE_OUT_OF_MEMORY; @@ -1416,19 +1472,10 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) /* free SSPI Schannel API credential handle */ if(connssl->cred) { - /* decrement the reference counter of the credential/session handle */ - if(connssl->cred->refcount > 0) { - connssl->cred->refcount--; - infof(data, "schannel: decremented credential handle refcount = %d\n", - connssl->cred->refcount); - } - - /* if the handle was not cached and the refcount is zero */ - if(!connssl->cred->cached && connssl->cred->refcount == 0) { - infof(data, "schannel: clear credential handle\n"); - s_pSecFn->FreeCredentialsHandle(&connssl->cred->cred_handle); - Curl_safefree(connssl->cred); - } + Curl_ssl_sessionid_lock(conn); + Curl_schannel_session_free(connssl->cred); + Curl_ssl_sessionid_unlock(conn); + connssl->cred = NULL; } /* free internal buffer for received encrypted data */ @@ -1450,16 +1497,13 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) void Curl_schannel_session_free(void *ptr) { + /* this is expected to be called under sessionid lock */ struct curl_schannel_cred *cred = ptr; - if(cred && cred->cached) { - if(cred->refcount == 0) { - s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); - Curl_safefree(cred); - } - else { - cred->cached = FALSE; - } + cred->refcount--; + if(cred->refcount == 0) { + s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); + Curl_safefree(cred); } } @@ -1480,32 +1524,35 @@ size_t Curl_schannel_version(char *buffer, size_t size) return size; } -int Curl_schannel_random(unsigned char *entropy, size_t length) +CURLcode Curl_schannel_random(unsigned char *entropy, size_t length) { HCRYPTPROV hCryptProv = 0; if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) - return 1; + return CURLE_FAILED_INIT; if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) { CryptReleaseContext(hCryptProv, 0UL); - return 1; + return CURLE_FAILED_INIT; } CryptReleaseContext(hCryptProv, 0UL); - return 0; + return CURLE_OK; } #ifdef _WIN32_WCE static CURLcode verify_certificate(struct connectdata *conn, int sockindex) { SECURITY_STATUS status; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; CURLcode result = CURLE_OK; CERT_CONTEXT *pCertContextServer = NULL; const CERT_CHAIN_CONTEXT *pChainContext = NULL; + const char * const conn_hostname = SSL_IS_PROXY() ? + conn->http_proxy.host.name : + conn->host.name; status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle, SECPKG_ATTR_REMOTE_CERT_CONTEXT, @@ -1527,7 +1574,7 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex) NULL, pCertContextServer->hCertStore, &ChainPara, - (data->set.ssl_no_revoke ? 0 : + (data->set.ssl.no_revoke ? 0 : CERT_CHAIN_REVOCATION_CHECK_CHAIN), NULL, &pChainContext)) { @@ -1563,15 +1610,10 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex) } if(result == CURLE_OK) { - if(data->set.ssl.verifyhost) { - TCHAR cert_hostname_buff[128]; - xcharp_u hostname; - xcharp_u cert_hostname; + if(conn->ssl_config.verifyhost) { + TCHAR cert_hostname_buff[256]; DWORD len; - cert_hostname.const_tchar_ptr = cert_hostname_buff; - hostname.tchar_ptr = Curl_convert_UTF8_to_tchar(conn->host.name); - /* TODO: Fix this for certificates with multiple alternative names. Right now we're only asking for the first preferred alternative name. Instead we'd need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG @@ -1582,31 +1624,50 @@ static CURLcode verify_certificate(struct connectdata *conn, int sockindex) */ len = CertGetNameString(pCertContextServer, CERT_NAME_DNS_TYPE, - 0, + CERT_NAME_DISABLE_IE4_UTF8_FLAG, NULL, - cert_hostname.tchar_ptr, - 128); - if(len > 0 && *cert_hostname.tchar_ptr == '*') { - /* this is a wildcard cert. try matching the last len - 1 chars */ - int hostname_len = strlen(conn->host.name); - cert_hostname.tchar_ptr++; - if(_tcsicmp(cert_hostname.const_tchar_ptr, - hostname.const_tchar_ptr + hostname_len - len + 2) != 0) - result = CURLE_PEER_FAILED_VERIFICATION; + cert_hostname_buff, + 256); + if(len > 0) { + const char *cert_hostname; + + /* Comparing the cert name and the connection hostname encoded as UTF-8 + * is acceptable since both values are assumed to use ASCII + * (or some equivalent) encoding + */ + cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname_buff); + if(!cert_hostname) { + result = CURLE_OUT_OF_MEMORY; + } + else{ + int match_result; + + match_result = Curl_cert_hostcheck(cert_hostname, conn->host.name); + if(match_result == CURL_HOST_MATCH) { + infof(data, + "schannel: connection hostname (%s) validated " + "against certificate name (%s)\n", + conn->host.name, + cert_hostname); + result = CURLE_OK; + } + else{ + failf(data, + "schannel: connection hostname (%s) " + "does not match certificate name (%s)", + conn->host.name, + cert_hostname); + result = CURLE_PEER_FAILED_VERIFICATION; + } + Curl_unicodefree(cert_hostname); + } } - else if(len == 0 || _tcsicmp(hostname.const_tchar_ptr, - cert_hostname.const_tchar_ptr) != 0) { + else { + failf(data, + "schannel: CertGetNameString did not provide any " + "certificate name information"); result = CURLE_PEER_FAILED_VERIFICATION; } - if(result == CURLE_PEER_FAILED_VERIFICATION) { - char *_cert_hostname; - _cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname.tchar_ptr); - failf(data, "schannel: CertGetNameString() certificate hostname " - "(%s) did not match connection (%s)", - _cert_hostname, conn->host.name); - Curl_unicodefree(_cert_hostname); - } - Curl_unicodefree(hostname.tchar_ptr); } } diff --git a/contrib/curl/lib/vtls/schannel.h b/contrib/curl/lib/vtls/schannel.h index a314b34f..8627c63c 100644 --- a/contrib/curl/lib/vtls/schannel.h +++ b/contrib/curl/lib/vtls/schannel.h @@ -8,7 +8,7 @@ * \___|\___/|_| \_\_____| * * Copyright (C) 2012, Marc Hoersken, , et al. - * Copyright (C) 2012 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -92,11 +92,14 @@ int Curl_schannel_init(void); void Curl_schannel_cleanup(void); size_t Curl_schannel_version(char *buffer, size_t size); -int Curl_schannel_random(unsigned char *entropy, size_t length); +CURLcode Curl_schannel_random(unsigned char *entropy, size_t length); /* Set the API backend definition to Schannel */ #define CURL_SSL_BACKEND CURLSSLBACKEND_SCHANNEL +/* this backend supports CURLOPT_CERTINFO */ +#define have_curlssl_certinfo 1 + /* API setup for Schannel */ #define curlssl_init Curl_schannel_init #define curlssl_cleanup Curl_schannel_cleanup diff --git a/contrib/curl/lib/vtls/vtls.c b/contrib/curl/lib/vtls/vtls.c index ca505a71..f40a9771 100644 --- a/contrib/curl/lib/vtls/vtls.c +++ b/contrib/curl/lib/vtls/vtls.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2017, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -61,10 +61,11 @@ #include "vtls.h" /* generic SSL protos etc */ #include "slist.h" #include "sendf.h" -#include "rawstr.h" +#include "strcase.h" #include "url.h" #include "progress.h" #include "share.h" +#include "multiif.h" #include "timeval.h" #include "curl_md5.h" #include "warnless.h" @@ -80,163 +81,56 @@ (data->share->specifier & \ (1<var) { \ + dest->var = strdup(source->var); \ + if(!dest->var) \ + return FALSE; \ + } \ + else \ + dest->var = NULL; bool -Curl_ssl_config_matches(struct ssl_config_data* data, - struct ssl_config_data* needle) +Curl_ssl_config_matches(struct ssl_primary_config* data, + struct ssl_primary_config* needle) { if((data->version == needle->version) && (data->verifypeer == needle->verifypeer) && (data->verifyhost == needle->verifyhost) && - safe_strequal(data->CApath, needle->CApath) && - safe_strequal(data->CAfile, needle->CAfile) && - safe_strequal(data->random_file, needle->random_file) && - safe_strequal(data->egdsocket, needle->egdsocket) && - safe_strequal(data->cipher_list, needle->cipher_list)) + Curl_safe_strcasecompare(data->CApath, needle->CApath) && + Curl_safe_strcasecompare(data->CAfile, needle->CAfile) && + Curl_safe_strcasecompare(data->clientcert, needle->clientcert) && + Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list)) return TRUE; return FALSE; } bool -Curl_clone_ssl_config(struct ssl_config_data *source, - struct ssl_config_data *dest) +Curl_clone_primary_ssl_config(struct ssl_primary_config *source, + struct ssl_primary_config *dest) { - dest->sessionid = source->sessionid; dest->verifyhost = source->verifyhost; dest->verifypeer = source->verifypeer; dest->version = source->version; - if(source->CAfile) { - dest->CAfile = strdup(source->CAfile); - if(!dest->CAfile) - return FALSE; - } - else - dest->CAfile = NULL; - - if(source->CApath) { - dest->CApath = strdup(source->CApath); - if(!dest->CApath) - return FALSE; - } - else - dest->CApath = NULL; - - if(source->cipher_list) { - dest->cipher_list = strdup(source->cipher_list); - if(!dest->cipher_list) - return FALSE; - } - else - dest->cipher_list = NULL; - - if(source->egdsocket) { - dest->egdsocket = strdup(source->egdsocket); - if(!dest->egdsocket) - return FALSE; - } - else - dest->egdsocket = NULL; - - if(source->random_file) { - dest->random_file = strdup(source->random_file); - if(!dest->random_file) - return FALSE; - } - else - dest->random_file = NULL; - + CLONE_STRING(CAfile); + CLONE_STRING(CApath); + CLONE_STRING(cipher_list); + CLONE_STRING(egdsocket); + CLONE_STRING(random_file); + CLONE_STRING(clientcert); return TRUE; } -void Curl_free_ssl_config(struct ssl_config_data* sslc) +void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc) { Curl_safefree(sslc->CAfile); Curl_safefree(sslc->CApath); Curl_safefree(sslc->cipher_list); Curl_safefree(sslc->egdsocket); Curl_safefree(sslc->random_file); -} - - -/* - * Curl_rand() returns a random unsigned integer, 32bit. - * - * This non-SSL function is put here only because this file is the only one - * with knowledge of what the underlying SSL libraries provide in terms of - * randomizers. - * - * NOTE: 'data' may be passed in as NULL when coming from external API without - * easy handle! - * - */ - -unsigned int Curl_rand(struct SessionHandle *data) -{ - unsigned int r = 0; - static unsigned int randseed; - static bool seeded = FALSE; - -#ifdef CURLDEBUG - char *force_entropy = getenv("CURL_ENTROPY"); - if(force_entropy) { - if(!seeded) { - size_t elen = strlen(force_entropy); - size_t clen = sizeof(randseed); - size_t min = elen < clen ? elen : clen; - memcpy((char *)&randseed, force_entropy, min); - seeded = TRUE; - } - else - randseed++; - return randseed; - } -#endif - - /* data may be NULL! */ - if(!Curl_ssl_random(data, (unsigned char *)&r, sizeof(r))) - return r; - - /* If Curl_ssl_random() returns non-zero it couldn't offer randomness and we - instead perform a "best effort" */ - -#ifdef RANDOM_FILE - if(!seeded) { - /* if there's a random file to read a seed from, use it */ - int fd = open(RANDOM_FILE, O_RDONLY); - if(fd > -1) { - /* read random data into the randseed variable */ - ssize_t nread = read(fd, &randseed, sizeof(randseed)); - if(nread == sizeof(randseed)) - seeded = TRUE; - close(fd); - } - } -#endif - - if(!seeded) { - struct timeval now = curlx_tvnow(); - infof(data, "WARNING: Using weak random seed\n"); - randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec; - randseed = randseed * 1103515245 + 12345; - randseed = randseed * 1103515245 + 12345; - randseed = randseed * 1103515245 + 12345; - seeded = TRUE; - } - - /* Return an unsigned 32-bit pseudo-random number. */ - r = randseed = randseed * 1103515245 + 12345; - return (r << 16) | ((r >> 16) & 0xFFFF); + Curl_safefree(sslc->clientcert); } int Curl_ssl_backend(void) @@ -276,22 +170,44 @@ void Curl_ssl_cleanup(void) } } -static bool ssl_prefs_check(struct SessionHandle *data) +static bool ssl_prefs_check(struct Curl_easy *data) { /* check for CURLOPT_SSLVERSION invalid parameter value */ - if((data->set.ssl.version < 0) - || (data->set.ssl.version >= CURL_SSLVERSION_LAST)) { + if((data->set.ssl.primary.version < 0) + || (data->set.ssl.primary.version >= CURL_SSLVERSION_LAST)) { failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION"); return FALSE; } return TRUE; } +static CURLcode +ssl_connect_init_proxy(struct connectdata *conn, int sockindex) +{ + DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]); + if(ssl_connection_complete == conn->ssl[sockindex].state && + !conn->proxy_ssl[sockindex].use) { +#if defined(HTTPS_PROXY_SUPPORT) + conn->proxy_ssl[sockindex] = conn->ssl[sockindex]; + memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex])); +#else + return CURLE_NOT_BUILT_IN; +#endif + } + return CURLE_OK; +} + CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex) { CURLcode result; + if(conn->bits.proxy_ssl_connected[sockindex]) { + result = ssl_connect_init_proxy(conn, sockindex); + if(result) + return result; + } + if(!ssl_prefs_check(conn->data)) return CURLE_SSL_CONNECT_ERROR; @@ -312,6 +228,11 @@ Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { CURLcode result; + if(conn->bits.proxy_ssl_connected[sockindex]) { + result = ssl_connect_init_proxy(conn, sockindex); + if(result) + return result; + } if(!ssl_prefs_check(conn->data)) return CURLE_SSL_CONNECT_ERROR; @@ -329,48 +250,76 @@ Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, return result; } +/* + * Lock shared SSL session data + */ +void Curl_ssl_sessionid_lock(struct connectdata *conn) +{ + if(SSLSESSION_SHARED(conn->data)) + Curl_share_lock(conn->data, + CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); +} + +/* + * Unlock shared SSL session data + */ +void Curl_ssl_sessionid_unlock(struct connectdata *conn) +{ + if(SSLSESSION_SHARED(conn->data)) + Curl_share_unlock(conn->data, CURL_LOCK_DATA_SSL_SESSION); +} + /* * Check if there's a session ID for the given connection in the cache, and if * there's one suitable, it is provided. Returns TRUE when no entry matched. */ bool Curl_ssl_getsessionid(struct connectdata *conn, void **ssl_sessionid, - size_t *idsize) /* set 0 if unknown */ + size_t *idsize, /* set 0 if unknown */ + int sockindex) { struct curl_ssl_session *check; - struct SessionHandle *data = conn->data; + struct Curl_easy *data = conn->data; size_t i; long *general_age; bool no_match = TRUE; + const bool isProxy = CONNECT_PROXY_SSL(); + struct ssl_primary_config * const ssl_config = isProxy ? + &conn->proxy_ssl_config : + &conn->ssl_config; + const char * const name = isProxy ? conn->http_proxy.host.name : + conn->host.name; + int port = isProxy ? (int)conn->port : conn->remote_port; *ssl_sessionid = NULL; - if(!conn->ssl_config.sessionid) + DEBUGASSERT(data->set.general_ssl.sessionid); + + if(!data->set.general_ssl.sessionid) /* session ID re-use is disabled */ return TRUE; /* Lock if shared */ - if(SSLSESSION_SHARED(data)) { - Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); + if(SSLSESSION_SHARED(data)) general_age = &data->share->sessionage; - } else general_age = &data->state.sessionage; - for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) { + for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) { check = &data->state.session[i]; if(!check->sessionid) /* not session ID means blank entry */ continue; - if(Curl_raw_equal(conn->host.name, check->name) && + if(strcasecompare(name, check->name) && ((!conn->bits.conn_to_host && !check->conn_to_host) || - (conn->bits.conn_to_host && check->conn_to_host && - Curl_raw_equal(conn->conn_to_host.name, check->conn_to_host))) && + (conn->bits.conn_to_host && check->conn_to_host && + strcasecompare(conn->conn_to_host.name, check->conn_to_host))) && ((!conn->bits.conn_to_port && check->conn_to_port == -1) || - (conn->bits.conn_to_port && check->conn_to_port != -1 && - conn->conn_to_port == check->conn_to_port)) && - (conn->remote_port == check->remote_port) && - Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) { + (conn->bits.conn_to_port && check->conn_to_port != -1 && + conn->conn_to_port == check->conn_to_port)) && + (port == check->remote_port) && + strcasecompare(conn->handler->scheme, check->scheme) && + Curl_ssl_config_matches(ssl_config, &check->ssl_config)) { /* yes, we have a session ID! */ (*general_age)++; /* increase general age */ check->age = *general_age; /* set this as used in this age */ @@ -382,10 +331,6 @@ bool Curl_ssl_getsessionid(struct connectdata *conn, } } - /* Unlock */ - if(SSLSESSION_SHARED(data)) - Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); - return no_match; } @@ -403,7 +348,7 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session) session->sessionid = NULL; session->age = 0; /* fresh */ - Curl_free_ssl_config(&session->ssl_config); + Curl_free_primary_ssl_config(&session->ssl_config); Curl_safefree(session->name); Curl_safefree(session->conn_to_host); @@ -416,12 +361,9 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session) void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) { size_t i; - struct SessionHandle *data=conn->data; + struct Curl_easy *data=conn->data; - if(SSLSESSION_SHARED(data)) - Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); - - for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) { + for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) { struct curl_ssl_session *check = &data->state.session[i]; if(check->sessionid == ssl_sessionid) { @@ -429,9 +371,6 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) break; } } - - if(SSLSESSION_SHARED(data)) - Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); } /* @@ -442,22 +381,25 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) */ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, void *ssl_sessionid, - size_t idsize) + size_t idsize, + int sockindex) { size_t i; - struct SessionHandle *data=conn->data; /* the mother of all structs */ + struct Curl_easy *data=conn->data; /* the mother of all structs */ struct curl_ssl_session *store = &data->state.session[0]; long oldest_age=data->state.session[0].age; /* zero if unused */ char *clone_host; char *clone_conn_to_host; int conn_to_port; long *general_age; + const bool isProxy = CONNECT_PROXY_SSL(); + struct ssl_primary_config * const ssl_config = isProxy ? + &conn->proxy_ssl_config : + &conn->ssl_config; - /* Even though session ID re-use might be disabled, that only disables USING - IT. We still store it here in case the re-using is again enabled for an - upcoming transfer */ + DEBUGASSERT(data->set.general_ssl.sessionid); - clone_host = strdup(conn->host.name); + clone_host = strdup(isProxy ? conn->http_proxy.host.name : conn->host.name); if(!clone_host) return CURLE_OUT_OF_MEMORY; /* bail out */ @@ -481,7 +423,6 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, /* If using shared SSL session, lock! */ if(SSLSESSION_SHARED(data)) { - Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); general_age = &data->share->sessionage; } else { @@ -489,14 +430,14 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, } /* find an empty slot for us, or find the oldest */ - for(i = 1; (i < data->set.ssl.max_ssl_sessions) && + for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) && data->state.session[i].sessionid; i++) { if(data->state.session[i].age < oldest_age) { oldest_age = data->state.session[i].age; store = &data->state.session[i]; } } - if(i == data->set.ssl.max_ssl_sessions) + if(i == data->set.general_ssl.max_ssl_sessions) /* cache is full, we must "kill" the oldest entry! */ Curl_ssl_kill_session(store); else @@ -506,19 +447,17 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, store->sessionid = ssl_sessionid; store->idsize = idsize; store->age = *general_age; /* set current age */ - /* free it if there's one already present */ + /* free it if there's one already present */ free(store->name); free(store->conn_to_host); store->name = clone_host; /* clone host name */ store->conn_to_host = clone_conn_to_host; /* clone connect to host name */ store->conn_to_port = conn_to_port; /* connect to port number */ - store->remote_port = conn->remote_port; /* port number */ + /* port number */ + store->remote_port = isProxy ? (int)conn->port : conn->remote_port; + store->scheme = conn->handler->scheme; - /* Unlock */ - if(SSLSESSION_SHARED(data)) - Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); - - if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) { + if(!Curl_clone_primary_ssl_config(ssl_config, &store->ssl_config)) { store->sessionid = NULL; /* let caller free sessionid */ free(clone_host); free(clone_conn_to_host); @@ -529,12 +468,12 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, } -void Curl_ssl_close_all(struct SessionHandle *data) +void Curl_ssl_close_all(struct Curl_easy *data) { size_t i; /* kill the session ID cache if not shared */ if(data->state.session && !SSLSESSION_SHARED(data)) { - for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) + for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) /* the single-killer function handles empty table slots */ Curl_ssl_kill_session(&data->state.session[i]); @@ -545,6 +484,43 @@ void Curl_ssl_close_all(struct SessionHandle *data) curlssl_close_all(data); } +#if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ + defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS) || \ + defined(USE_MBEDTLS) +int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks) +{ + struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; + + if(!numsocks) + return GETSOCK_BLANK; + + if(connssl->connecting_state == ssl_connect_2_writing) { + /* write mode */ + socks[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_WRITESOCK(0); + } + else if(connssl->connecting_state == ssl_connect_2_reading) { + /* read mode */ + socks[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_READSOCK(0); + } + + return GETSOCK_BLANK; +} +#else +int Curl_ssl_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) +{ + (void)conn; + (void)socks; + (void)numsocks; + return GETSOCK_BLANK; +} +/* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL || USE_DARWINSSL || USE_NSS */ +#endif + void Curl_ssl_close(struct connectdata *conn, int sockindex) { DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); @@ -567,20 +543,20 @@ CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex) /* Selects an SSL crypto engine */ -CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine) +CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine) { return curlssl_set_engine(data, engine); } /* Selects the default SSL crypto engine */ -CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data) +CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data) { return curlssl_set_engine_default(data); } /* Return list of OpenSSL crypto engine names. */ -struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data) +struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data) { return curlssl_engines_list(data); } @@ -589,7 +565,7 @@ struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data) * This sets up a session ID cache to the specified size. Make sure this code * is agnostic to what underlying SSL technology we use. */ -CURLcode Curl_ssl_initsessions(struct SessionHandle *data, size_t amount) +CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount) { struct curl_ssl_session *session; @@ -602,7 +578,7 @@ CURLcode Curl_ssl_initsessions(struct SessionHandle *data, size_t amount) return CURLE_OUT_OF_MEMORY; /* store the info in the SSL section */ - data->set.ssl.max_ssl_sessions = amount; + data->set.general_ssl.max_ssl_sessions = amount; data->state.session = session; data->state.sessionage = 1; /* this is brand new */ return CURLE_OK; @@ -632,7 +608,7 @@ bool Curl_ssl_data_pending(const struct connectdata *conn, return curlssl_data_pending(conn, connindex); } -void Curl_ssl_free_certinfo(struct SessionHandle *data) +void Curl_ssl_free_certinfo(struct Curl_easy *data) { int i; struct curl_certinfo *ci = &data->info.certs; @@ -650,7 +626,7 @@ void Curl_ssl_free_certinfo(struct SessionHandle *data) } } -CURLcode Curl_ssl_init_certinfo(struct SessionHandle *data, int num) +CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num) { struct curl_certinfo *ci = &data->info.certs; struct curl_slist **table; @@ -672,15 +648,15 @@ CURLcode Curl_ssl_init_certinfo(struct SessionHandle *data, int num) /* * 'value' is NOT a zero terminated string */ -CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle *data, +CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, int certnum, const char *label, const char *value, size_t valuelen) { - struct curl_certinfo * ci = &data->info.certs; - char * output; - struct curl_slist * nl; + struct curl_certinfo *ci = &data->info.certs; + char *output; + struct curl_slist *nl; CURLcode result = CURLE_OK; size_t labellen = strlen(label); size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */ @@ -713,7 +689,7 @@ CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle *data, * This is a convenience function for push_certinfo_len that takes a zero * terminated value. */ -CURLcode Curl_ssl_push_certinfo(struct SessionHandle *data, +CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, int certnum, const char *label, const char *value) @@ -723,9 +699,9 @@ CURLcode Curl_ssl_push_certinfo(struct SessionHandle *data, return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen); } -int Curl_ssl_random(struct SessionHandle *data, - unsigned char *entropy, - size_t length) +CURLcode Curl_ssl_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length) { return curlssl_random(data, entropy, length); } @@ -792,7 +768,7 @@ static CURLcode pubkey_pem_to_der(const char *pem, * Generic pinned public key check. */ -CURLcode Curl_pin_peer_pubkey(struct SessionHandle *data, +CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, const char *pinnedpubkey, const unsigned char *pubkey, size_t pubkeylen) { diff --git a/contrib/curl/lib/vtls/vtls.h b/contrib/curl/lib/vtls/vtls.h index 31ba9fc5..2aabeda2 100644 --- a/contrib/curl/lib/vtls/vtls.h +++ b/contrib/curl/lib/vtls/vtls.h @@ -50,13 +50,24 @@ #define ALPN_HTTP_1_1_LENGTH 8 #define ALPN_HTTP_1_1 "http/1.1" -bool Curl_ssl_config_matches(struct ssl_config_data* data, - struct ssl_config_data* needle); -bool Curl_clone_ssl_config(struct ssl_config_data* source, - struct ssl_config_data* dest); -void Curl_free_ssl_config(struct ssl_config_data* sslc); +/* set of helper macros for the backends to access the correct fields. For the + proxy or for the remote host - to properly support HTTPS proxy */ -unsigned int Curl_rand(struct SessionHandle *); +#define SSL_IS_PROXY() (CURLPROXY_HTTPS == conn->http_proxy.proxytype && \ + ssl_connection_complete != conn->proxy_ssl[conn->sock[SECONDARYSOCKET] == \ + CURL_SOCKET_BAD ? FIRSTSOCKET : SECONDARYSOCKET].state) +#define SSL_SET_OPTION(var) (SSL_IS_PROXY() ? data->set.proxy_ssl.var : \ + data->set.ssl.var) +#define SSL_CONN_CONFIG(var) (SSL_IS_PROXY() ? \ + conn->proxy_ssl_config.var : conn->ssl_config.var) + +bool Curl_ssl_config_matches(struct ssl_primary_config* data, + struct ssl_primary_config* needle); +bool Curl_clone_primary_ssl_config(struct ssl_primary_config *source, + struct ssl_primary_config *dest); +void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc); +int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks); int Curl_ssl_backend(void); @@ -69,16 +80,16 @@ CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn, bool *done); /* tell the SSL stuff to close down all open information regarding connections (and thus session ID caching etc) */ -void Curl_ssl_close_all(struct SessionHandle *data); +void Curl_ssl_close_all(struct Curl_easy *data); void Curl_ssl_close(struct connectdata *conn, int sockindex); CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex); -CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine); +CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine); /* Sets engine as default for all SSL operations */ -CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data); -struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data); +CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data); +struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data); /* init the SSL session ID cache */ -CURLcode Curl_ssl_initsessions(struct SessionHandle *, size_t); +CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t); size_t Curl_ssl_version(char *buffer, size_t size); bool Curl_ssl_data_pending(const struct connectdata *conn, int connindex); @@ -86,39 +97,71 @@ int Curl_ssl_check_cxn(struct connectdata *conn); /* Certificate information list handling. */ -void Curl_ssl_free_certinfo(struct SessionHandle *data); -CURLcode Curl_ssl_init_certinfo(struct SessionHandle * data, int num); -CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle * data, int certnum, - const char * label, const char * value, +void Curl_ssl_free_certinfo(struct Curl_easy *data); +CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num); +CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, int certnum, + const char *label, const char *value, size_t valuelen); -CURLcode Curl_ssl_push_certinfo(struct SessionHandle * data, int certnum, - const char * label, const char * value); +CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, int certnum, + const char *label, const char *value); /* Functions to be used by SSL library adaptation functions */ -/* extract a session ID */ +/* Lock session cache mutex. + * Call this before calling other Curl_ssl_*session* functions + * Caller should unlock this mutex as soon as possible, as it may block + * other SSL connection from making progress. + * The purpose of explicitly locking SSL session cache data is to allow + * individual SSL engines to manage session lifetime in their specific way. + */ +void Curl_ssl_sessionid_lock(struct connectdata *conn); + +/* Unlock session cache mutex */ +void Curl_ssl_sessionid_unlock(struct connectdata *conn); + +/* extract a session ID + * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). + * Caller must make sure that the ownership of returned sessionid object + * is properly taken (e.g. its refcount is incremented + * under sessionid mutex). + */ bool Curl_ssl_getsessionid(struct connectdata *conn, void **ssl_sessionid, - size_t *idsize); /* set 0 if unknown */ -/* add a new session ID */ + size_t *idsize, /* set 0 if unknown */ + int sockindex); +/* add a new session ID + * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). + * Caller must ensure that it has properly shared ownership of this sessionid + * object with cache (e.g. incrementing refcount on success) + */ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, void *ssl_sessionid, - size_t idsize); -/* Kill a single session ID entry in the cache */ + size_t idsize, + int sockindex); +/* Kill a single session ID entry in the cache + * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). + * This will call engine-specific curlssl_session_free function, which must + * take sessionid object ownership from sessionid cache + * (e.g. decrement refcount). + */ void Curl_ssl_kill_session(struct curl_ssl_session *session); -/* delete a session from the cache */ +/* delete a session from the cache + * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock). + * This will call engine-specific curlssl_session_free function, which must + * take sessionid object ownership from sessionid cache + * (e.g. decrement refcount). + */ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid); -/* get N random bytes into the buffer, return 0 if a find random is filled - in */ -int Curl_ssl_random(struct SessionHandle *data, unsigned char *buffer, - size_t length); +/* get N random bytes into the buffer */ +CURLcode Curl_ssl_random(struct Curl_easy *data, unsigned char *buffer, + size_t length); CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */ size_t tmplen, unsigned char *md5sum, /* output */ size_t md5len); /* Check pinned public key. */ -CURLcode Curl_pin_peer_pubkey(struct SessionHandle *data, +CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, const char *pinnedpubkey, const unsigned char *pubkey, size_t pubkeylen); diff --git a/contrib/curl/lib/wildcard.h b/contrib/curl/lib/wildcard.h index 7d66992b..7f61cd17 100644 --- a/contrib/curl/lib/wildcard.h +++ b/contrib/curl/lib/wildcard.h @@ -53,6 +53,6 @@ struct WildcardData { CURLcode Curl_wildcard_init(struct WildcardData *wc); void Curl_wildcard_dtor(struct WildcardData *wc); -struct SessionHandle; +struct Curl_easy; #endif /* HEADER_CURL_WILDCARD_H */ diff --git a/contrib/curl/lib/x509asn1.c b/contrib/curl/lib/x509asn1.c index c221ba07..c4bc7c1f 100644 --- a/contrib/curl/lib/x509asn1.c +++ b/contrib/curl/lib/x509asn1.c @@ -23,11 +23,11 @@ #include "curl_setup.h" #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \ - defined(USE_CYASSL) + defined(USE_CYASSL) || defined(USE_SCHANNEL) #include #include "urldata.h" -#include "strequal.h" +#include "strcase.h" #include "hostcheck.h" #include "vtls/vtls.h" #include "sendf.h" @@ -40,6 +40,9 @@ #include "curl_memory.h" #include "memdebug.h" +/* For overflow checks. */ +#define CURL_SIZE_T_MAX ((size_t)-1) + /* ASN.1 OIDs. */ static const char cnOID[] = "2.5.4.3"; /* Common name. */ @@ -105,8 +108,8 @@ static const curl_OID OIDtable[] = { */ -const char * Curl_getASN1Element(curl_asn1Element * elem, - const char * beg, const char * end) +const char *Curl_getASN1Element(curl_asn1Element *elem, + const char *beg, const char *end) { unsigned char b; unsigned long len; @@ -116,8 +119,8 @@ const char * Curl_getASN1Element(curl_asn1Element * elem, ending at `end'. Returns a pointer in source string after the parsed element, or NULL if an error occurs. */ - - if(beg >= end || !*beg) + if(!beg || !end || beg >= end || !*beg || + (size_t)(end - beg) > CURL_ASN1_MAX) return (const char *) NULL; /* Process header byte. */ @@ -152,7 +155,7 @@ const char * Curl_getASN1Element(curl_asn1Element * elem, elem->end = beg; return beg + 1; } - else if(beg + b > end) + else if((unsigned)b > (size_t)(end - beg)) return (const char *) NULL; /* Does not fit in source. */ else { /* Get long length. */ @@ -163,28 +166,28 @@ const char * Curl_getASN1Element(curl_asn1Element * elem, len = (len << 8) | (unsigned char) *beg++; } while(--b); } - if((unsigned long) (end - beg) < len) + if(len > (size_t)(end - beg)) return (const char *) NULL; /* Element data does not fit in source. */ elem->beg = beg; elem->end = beg + len; return elem->end; } -static const curl_OID * searchOID(const char * oid) +static const curl_OID * searchOID(const char *oid) { - const curl_OID * op; + const curl_OID *op; /* Search the null terminated OID or OID identifier in local table. Return the table entry pointer or NULL if not found. */ for(op = OIDtable; op->numoid; op++) - if(!strcmp(op->numoid, oid) || curl_strequal(op->textoid, oid)) + if(!strcmp(op->numoid, oid) || strcasecompare(op->textoid, oid)) return op; return (const curl_OID *) NULL; } -static const char * bool2str(const char * beg, const char * end) +static const char *bool2str(const char *beg, const char *end) { /* Convert an ASN.1 Boolean value into its string representation. Return the dynamically allocated string, or NULL if source is not an @@ -195,22 +198,24 @@ static const char * bool2str(const char * beg, const char * end) return strdup(*beg? "TRUE": "FALSE"); } -static const char * octet2str(const char * beg, const char * end) +static const char *octet2str(const char *beg, const char *end) { size_t n = end - beg; - char * buf; + char *buf = NULL; /* Convert an ASN.1 octet string to a printable string. Return the dynamically allocated string, or NULL if an error occurs. */ - buf = malloc(3 * n + 1); - if(buf) - for(n = 0; beg < end; n += 3) - snprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++); + if(n <= (CURL_SIZE_T_MAX - 1) / 3) { + buf = malloc(3 * n + 1); + if(buf) + for(n = 0; beg < end; n += 3) + snprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++); + } return buf; } -static const char * bit2str(const char * beg, const char * end) +static const char *bit2str(const char *beg, const char *end) { /* Convert an ASN.1 bit string to a printable string. Return the dynamically allocated string, or NULL if an error occurs. */ @@ -220,7 +225,7 @@ static const char * bit2str(const char * beg, const char * end) return octet2str(beg, end); } -static const char * int2str(const char * beg, const char * end) +static const char *int2str(const char *beg, const char *end) { long val = 0; size_t n = end - beg; @@ -246,14 +251,14 @@ static const char * int2str(const char * beg, const char * end) } static ssize_t -utf8asn1str(char * * to, int type, const char * from, const char * end) +utf8asn1str(char **to, int type, const char *from, const char *end) { size_t inlength = end - from; int size = 1; size_t outlength; int charsize; unsigned int wc; - char * buf; + char *buf; /* Perform a lazy conversion from an ASN.1 typed string to UTF8. Allocate the destination buffer dynamically. The allocation size will normally be too @@ -262,7 +267,7 @@ utf8asn1str(char * * to, int type, const char * from, const char * end) string length. */ *to = (char *) NULL; - switch (type) { + switch(type) { case CURL_ASN1_BMP_STRING: size = 2; break; @@ -282,6 +287,8 @@ utf8asn1str(char * * to, int type, const char * from, const char * end) if(inlength % size) return -1; /* Length inconsistent with character size. */ + if(inlength / size > (CURL_SIZE_T_MAX - 1) / 4) + return -1; /* Too big. */ buf = malloc(4 * (inlength / size) + 1); if(!buf) return -1; /* Not enough memory. */ @@ -295,7 +302,7 @@ utf8asn1str(char * * to, int type, const char * from, const char * end) else { for(outlength = 0; from < end;) { wc = 0; - switch (size) { + switch(size) { case 4: wc = (wc << 8) | *(const unsigned char *) from++; wc = (wc << 8) | *(const unsigned char *) from++; @@ -335,9 +342,9 @@ utf8asn1str(char * * to, int type, const char * from, const char * end) return outlength; } -static const char * string2str(int type, const char * beg, const char * end) +static const char *string2str(int type, const char *beg, const char *end) { - char * buf; + char *buf; /* Convert an ASN.1 String into its UTF-8 string representation. Return the dynamically allocated string, or NULL if an error occurs. */ @@ -347,7 +354,7 @@ static const char * string2str(int type, const char * beg, const char * end) return buf; } -static int encodeUint(char * buf, int n, unsigned int x) +static int encodeUint(char *buf, int n, unsigned int x) { int i = 0; unsigned int y = x / 10; @@ -367,7 +374,7 @@ static int encodeUint(char * buf, int n, unsigned int x) return i; } -static int encodeOID(char * buf, int n, const char * beg, const char * end) +static int encodeOID(char *buf, int n, const char *beg, const char *end) { int i = 0; unsigned int x; @@ -406,9 +413,9 @@ static int encodeOID(char * buf, int n, const char * beg, const char * end) return i; } -static const char * OID2str(const char * beg, const char * end, bool symbolic) +static const char *OID2str(const char *beg, const char *end, bool symbolic) { - char * buf = (char *) NULL; + char *buf = (char *) NULL; const curl_OID * op; int n; @@ -436,14 +443,14 @@ static const char * OID2str(const char * beg, const char * end, bool symbolic) return buf; } -static const char * GTime2str(const char * beg, const char * end) +static const char *GTime2str(const char *beg, const char *end) { - const char * tzp; - const char * fracp; + const char *tzp; + const char *fracp; char sec1, sec2; size_t fracl; size_t tzl; - const char * sep = ""; + const char *sep = ""; /* Convert an ASN.1 Generalized time to a printable string. Return the dynamically allocated string, or NULL if an error occurs. */ @@ -453,7 +460,7 @@ static const char * GTime2str(const char * beg, const char * end) /* Get seconds digits. */ sec1 = '0'; - switch (fracp - beg - 12) { + switch(fracp - beg - 12) { case 0: sec2 = '0'; break; @@ -499,11 +506,11 @@ static const char * GTime2str(const char * beg, const char * end) sep, tzl, tzp); } -static const char * UTime2str(const char * beg, const char * end) +static const char *UTime2str(const char *beg, const char *end) { - const char * tzp; + const char *tzp; size_t tzl; - const char * sec; + const char *sec; /* Convert an ASN.1 UTC time to a printable string. Return the dynamically allocated string, or NULL if an error occurs. */ @@ -512,7 +519,7 @@ static const char * UTime2str(const char * beg, const char * end) ; /* Get the seconds. */ sec = beg + 10; - switch (tzp - sec) { + switch(tzp - sec) { case 0: sec = "00"; case 2: @@ -538,7 +545,7 @@ static const char * UTime2str(const char * beg, const char * end) tzl, tzp); } -const char * Curl_ASN1tostr(curl_asn1Element * elem, int type) +const char *Curl_ASN1tostr(curl_asn1Element *elem, int type) { /* Convert an ASN.1 element to a printable string. Return the dynamically allocated string, or NULL if an error occurs. */ @@ -549,7 +556,7 @@ const char * Curl_ASN1tostr(curl_asn1Element * elem, int type) if(!type) type = elem->tag; /* Type not forced: use element tag as type. */ - switch (type) { + switch(type) { case CURL_ASN1_BOOLEAN: return bool2str(elem->beg, elem->end); case CURL_ASN1_INTEGER: @@ -581,17 +588,17 @@ const char * Curl_ASN1tostr(curl_asn1Element * elem, int type) return (const char *) NULL; /* Unsupported. */ } -static ssize_t encodeDN(char * buf, size_t n, curl_asn1Element * dn) +static ssize_t encodeDN(char *buf, size_t n, curl_asn1Element *dn) { curl_asn1Element rdn; curl_asn1Element atv; curl_asn1Element oid; curl_asn1Element value; size_t l = 0; - const char * p1; - const char * p2; - const char * p3; - const char * str; + const char *p1; + const char *p2; + const char *p3; + const char *str; /* ASCII encode distinguished name at `dn' into the `n'-byte buffer at `buf'. Return the total string length, even if larger than `n'. */ @@ -647,9 +654,9 @@ static ssize_t encodeDN(char * buf, size_t n, curl_asn1Element * dn) return l; } -const char * Curl_DNtostr(curl_asn1Element * dn) +const char *Curl_DNtostr(curl_asn1Element *dn) { - char * buf = (char *) NULL; + char *buf = (char *) NULL; ssize_t n = encodeDN(buf, 0, dn); /* Convert an ASN.1 distinguished name into a printable string. @@ -669,12 +676,12 @@ const char * Curl_DNtostr(curl_asn1Element * dn) * X509 parser. */ -void Curl_parseX509(curl_X509certificate * cert, - const char * beg, const char * end) +int Curl_parseX509(curl_X509certificate *cert, + const char *beg, const char *end) { curl_asn1Element elem; curl_asn1Element tbsCertificate; - const char * ccp; + const char *ccp; static const char defaultVersion = 0; /* v1. */ /* ASN.1 parse an X509 certificate into structure subfields. @@ -686,7 +693,8 @@ void Curl_parseX509(curl_X509certificate * cert, cert->certificate.end = end; /* Get the sequence content. */ - Curl_getASN1Element(&elem, beg, end); + if(!Curl_getASN1Element(&elem, beg, end)) + return -1; /* Invalid bounds/size. */ beg = elem.beg; end = elem.end; @@ -749,9 +757,10 @@ void Curl_parseX509(curl_X509certificate * cert, } if(elem.tag == 3) Curl_getASN1Element(&cert->extensions, elem.beg, elem.end); + return 0; } -static size_t copySubstring(char * to, const char * from) +static size_t copySubstring(char *to, const char *from) { size_t i; @@ -768,8 +777,8 @@ static size_t copySubstring(char * to, const char * from) return i; } -static const char * dumpAlgo(curl_asn1Element * param, - const char * beg, const char * end) +static const char *dumpAlgo(curl_asn1Element *param, + const char *beg, const char *end) { curl_asn1Element oid; @@ -784,10 +793,10 @@ static const char * dumpAlgo(curl_asn1Element * param, return OID2str(oid.beg, oid.end, TRUE); } -static void do_pubkey_field(struct SessionHandle * data, int certnum, - const char * label, curl_asn1Element * elem) +static void do_pubkey_field(struct Curl_easy *data, int certnum, + const char *label, curl_asn1Element *elem) { - const char * output; + const char *output; /* Generate a certificate information record for the public key. */ @@ -801,14 +810,14 @@ static void do_pubkey_field(struct SessionHandle * data, int certnum, } } -static void do_pubkey(struct SessionHandle * data, int certnum, - const char * algo, curl_asn1Element * param, - curl_asn1Element * pubkey) +static void do_pubkey(struct Curl_easy *data, int certnum, + const char *algo, curl_asn1Element *param, + curl_asn1Element *pubkey) { curl_asn1Element elem; curl_asn1Element pk; - const char * p; - const char * q; + const char *p; + const char *q; unsigned long len; unsigned int i; @@ -817,7 +826,7 @@ static void do_pubkey(struct SessionHandle * data, int certnum, /* Get the public key (single element). */ Curl_getASN1Element(&pk, pubkey->beg + 1, pubkey->end); - if(curl_strequal(algo, "rsaEncryption")) { + if(strcasecompare(algo, "rsaEncryption")) { p = Curl_getASN1Element(&elem, pk.beg, pk.end); /* Compute key length. */ for(q = elem.beg; !*q && q < elem.end; q++) @@ -842,7 +851,7 @@ static void do_pubkey(struct SessionHandle * data, int certnum, Curl_getASN1Element(&elem, p, pk.end); do_pubkey_field(data, certnum, "rsa(e)", &elem); } - else if(curl_strequal(algo, "dsa")) { + else if(strcasecompare(algo, "dsa")) { p = Curl_getASN1Element(&elem, param->beg, param->end); do_pubkey_field(data, certnum, "dsa(p)", &elem); p = Curl_getASN1Element(&elem, p, param->end); @@ -851,7 +860,7 @@ static void do_pubkey(struct SessionHandle * data, int certnum, do_pubkey_field(data, certnum, "dsa(g)", &elem); do_pubkey_field(data, certnum, "dsa(pub_key)", &pk); } - else if(curl_strequal(algo, "dhpublicnumber")) { + else if(strcasecompare(algo, "dhpublicnumber")) { p = Curl_getASN1Element(&elem, param->beg, param->end); do_pubkey_field(data, certnum, "dh(p)", &elem); Curl_getASN1Element(&elem, param->beg, param->end); @@ -859,24 +868,24 @@ static void do_pubkey(struct SessionHandle * data, int certnum, do_pubkey_field(data, certnum, "dh(pub_key)", &pk); } #if 0 /* Patent-encumbered. */ - else if(curl_strequal(algo, "ecPublicKey")) { + else if(strcasecompare(algo, "ecPublicKey")) { /* Left TODO. */ } #endif } -CURLcode Curl_extract_certinfo(struct connectdata * conn, +CURLcode Curl_extract_certinfo(struct connectdata *conn, int certnum, - const char * beg, - const char * end) + const char *beg, + const char *end) { curl_X509certificate cert; - struct SessionHandle * data = conn->data; + struct Curl_easy *data = conn->data; curl_asn1Element param; - const char * ccp; - char * cp1; + const char *ccp; + char *cp1; size_t cl1; - char * cp2; + char *cp2; CURLcode result; unsigned long version; size_t i; @@ -889,7 +898,8 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn, /* Prepare the certificate information for curl_easy_getinfo(). */ /* Extract the certificate ASN.1 elements. */ - Curl_parseX509(&cert, beg, end); + if(Curl_parseX509(&cert, beg, end)) + return CURLE_OUT_OF_MEMORY; /* Subject. */ ccp = Curl_DNtostr(&cert.subject); @@ -1025,16 +1035,16 @@ CURLcode Curl_extract_certinfo(struct connectdata * conn, return CURLE_OK; } -#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL */ +#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL or USE_SCHANNEL */ #if defined(USE_GSKIT) -static const char * checkOID(const char * beg, const char * end, - const char * oid) +static const char *checkOID(const char *beg, const char *end, + const char *oid) { curl_asn1Element e; - const char * ccp; - const char * p; + const char *ccp; + const char *p; bool matched; /* Check if first ASN.1 element at `beg' is the given OID. @@ -1053,21 +1063,26 @@ static const char * checkOID(const char * beg, const char * end, return matched? ccp: (const char *) NULL; } -CURLcode Curl_verifyhost(struct connectdata * conn, - const char * beg, const char * end) +CURLcode Curl_verifyhost(struct connectdata *conn, + const char *beg, const char *end) { - struct SessionHandle * data = conn->data; + struct Curl_easy *data = conn->data; curl_X509certificate cert; curl_asn1Element dn; curl_asn1Element elem; curl_asn1Element ext; curl_asn1Element name; - const char * p; - const char * q; - char * dnsname; + const char *p; + const char *q; + char *dnsname; int matched = -1; size_t addrlen = (size_t) -1; ssize_t len; + const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name: + conn->host.name; + const char * const dispname = SSL_IS_PROXY()? + conn->http_proxy.host.dispname: + conn->host.dispname; #ifdef ENABLE_IPV6 struct in6_addr addr; #else @@ -1077,20 +1092,19 @@ CURLcode Curl_verifyhost(struct connectdata * conn, /* Verify that connection server matches info in X509 certificate at `beg'..`end'. */ - if(!data->set.ssl.verifyhost) + if(!SSL_CONN_CONFIG(verifyhost)) return CURLE_OK; - if(!beg) + if(Curl_parseX509(&cert, beg, end)) return CURLE_PEER_FAILED_VERIFICATION; - Curl_parseX509(&cert, beg, end); /* Get the server IP address. */ #ifdef ENABLE_IPV6 - if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, conn->host.name, &addr)) + if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, hostname, &addr)) addrlen = sizeof(struct in6_addr); else #endif - if(Curl_inet_pton(AF_INET, conn->host.name, &addr)) + if(Curl_inet_pton(AF_INET, hostname, &addr)) addrlen = sizeof(struct in_addr); /* Process extensions. */ @@ -1108,12 +1122,12 @@ CURLcode Curl_verifyhost(struct connectdata * conn, /* Check all GeneralNames. */ for(q = elem.beg; matched != 1 && q < elem.end;) { q = Curl_getASN1Element(&name, q, elem.end); - switch (name.tag) { + switch(name.tag) { case 2: /* DNS name. */ len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING, name.beg, name.end); if(len > 0 && (size_t)len == strlen(dnsname)) - matched = Curl_cert_hostcheck(dnsname, conn->host.name); + matched = Curl_cert_hostcheck(dnsname, hostname); else matched = 0; free(dnsname); @@ -1128,15 +1142,15 @@ CURLcode Curl_verifyhost(struct connectdata * conn, } } - switch (matched) { + switch(matched) { case 1: /* an alternative name matched the server hostname */ - infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname); + infof(data, "\t subjectAltName: %s matched\n", dispname); return CURLE_OK; case 0: /* an alternative name field existed, but didn't match and then we MUST fail */ - infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname); + infof(data, "\t subjectAltName does not match %s\n", dispname); return CURLE_PEER_FAILED_VERIFICATION; } @@ -1168,14 +1182,14 @@ CURLcode Curl_verifyhost(struct connectdata * conn, } if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */ failf(data, "SSL: illegal cert name field"); - else if(Curl_cert_hostcheck((const char *) dnsname, conn->host.name)) { + else if(Curl_cert_hostcheck((const char *) dnsname, hostname)) { infof(data, "\t common name: %s (matched)\n", dnsname); free(dnsname); return CURLE_OK; } else failf(data, "SSL: certificate subject name '%s' does not match " - "target host name '%s'", dnsname, conn->host.dispname); + "target host name '%s'", dnsname, dispname); free(dnsname); } diff --git a/contrib/curl/lib/x509asn1.h b/contrib/curl/lib/x509asn1.h index e6a1e244..ce402979 100644 --- a/contrib/curl/lib/x509asn1.h +++ b/contrib/curl/lib/x509asn1.h @@ -8,7 +8,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2015, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2016, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,7 +26,7 @@ #include "curl_setup.h" #if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \ - defined(USE_CYASSL) + defined(USE_CYASSL) || defined(USE_SCHANNEL) #include "urldata.h" @@ -34,6 +34,9 @@ * Constants. */ +/* Largest supported ASN.1 structure. */ +#define CURL_ASN1_MAX ((size_t) 0x40000) /* 256K */ + /* ASN.1 classes. */ #define CURL_ASN1_UNIVERSAL 0 #define CURL_ASN1_APPLICATION 1 @@ -117,16 +120,15 @@ typedef struct { * Prototypes. */ -const char * Curl_getASN1Element(curl_asn1Element * elem, - const char * beg, const char * end); -const char * Curl_ASN1tostr(curl_asn1Element * elem, int type); -const char * Curl_DNtostr(curl_asn1Element * dn); -void Curl_parseX509(curl_X509certificate * cert, - const char * beg, const char * end); -CURLcode Curl_extract_certinfo(struct connectdata * conn, int certnum, - const char * beg, const char * end); -CURLcode Curl_verifyhost(struct connectdata * conn, - const char * beg, const char * end); - -#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL */ +const char *Curl_getASN1Element(curl_asn1Element *elem, + const char *beg, const char *end); +const char *Curl_ASN1tostr(curl_asn1Element *elem, int type); +const char *Curl_DNtostr(curl_asn1Element *dn); +int Curl_parseX509(curl_X509certificate *cert, + const char *beg, const char *end); +CURLcode Curl_extract_certinfo(struct connectdata *conn, int certnum, + const char *beg, const char *end); +CURLcode Curl_verifyhost(struct connectdata *conn, + const char *beg, const char *end); +#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL or USE_SCHANNEL */ #endif /* HEADER_CURL_X509ASN1_H */ diff --git a/contrib/curl/premake5.lua b/contrib/curl/premake5.lua index 77be654d..e483f156 100644 --- a/contrib/curl/premake5.lua +++ b/contrib/curl/premake5.lua @@ -18,6 +18,7 @@ project "curl-lib" filter { "system:windows" } defines { "USE_SCHANNEL", "USE_WINDOWS_SSPI" } + links "crypt32" filter { "system:macosx" } defines { "USE_DARWINSSL" } From d285fa68a6e79aa849b90802a9ce99a6f849a54a Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Tue, 31 Jan 2017 12:10:40 -0800 Subject: [PATCH 14/59] Refactor language flags to go through the language API. So you can use 'language "C++11"' instead of 'flags { "C++11" }' --- modules/codelite/codelite.lua | 2 +- modules/codelite/codelite_project.lua | 17 +- .../codelite/tests/test_codelite_config.lua | 5 +- modules/d/_preload.lua | 2 + modules/d/actions/gmake.lua | 2 +- modules/xcode/xcode_common.lua | 43 +- src/_manifest.lua | 1 + src/_premake_init.lua | 25 +- src/actions/make/_make.lua | 2 +- src/actions/make/make_cpp.lua | 2 +- src/actions/vstudio/_vstudio.lua | 18 +- src/actions/vstudio/vs2005.lua | 4 +- src/actions/vstudio/vs200x_vcproj.lua | 2 +- src/actions/vstudio/vs2010.lua | 9 +- src/actions/vstudio/vs2010_nuget.lua | 6 +- src/actions/vstudio/vs2010_vcxproj.lua | 4488 ++++++++--------- src/base/config.lua | 2 +- src/base/languages.lua | 68 + src/base/oven.lua | 4 +- src/base/project.lua | 44 +- src/base/validation.lua | 14 +- src/tools/gcc.lua | 20 + 22 files changed, 2455 insertions(+), 2325 deletions(-) create mode 100644 src/base/languages.lua diff --git a/modules/codelite/codelite.lua b/modules/codelite/codelite.lua index ea1be19e..5f5dbd33 100755 --- a/modules/codelite/codelite.lua +++ b/modules/codelite/codelite.lua @@ -46,7 +46,7 @@ p.indent(" ") p.escaper(codelite.esc) - if project.iscpp(prj) then + if project.isc(prj) or project.iscpp(prj) then p.generate(prj, ".project", codelite.project.generate) end end diff --git a/modules/codelite/codelite_project.lua b/modules/codelite/codelite_project.lua index 0169e25f..b842e8a4 100755 --- a/modules/codelite/codelite_project.lua +++ b/modules/codelite/codelite_project.lua @@ -51,9 +51,9 @@ error("Invalid toolset '" + (_OPTIONS.cc or cfg.toolset) + "'") end - if cfg.language == "C" then + if p.languages.isc(cfg.language) then return m.ctools[tool] - elseif cfg.language == "C++" then + elseif p.languages.iscpp(cfg.language) then return m.cxxtools[tool] end end @@ -354,8 +354,19 @@ _p(3, '') end + function m.isCpp11(cfg) + return (cfg.language == 'gnu++11') or (cfg.language == 'C++11') or cfg.flags["C++11"] + end + + function m.isCpp14(cfg) + return (cfg.language == 'gnu++14') or (cfg.language == 'C++14') or cfg.flags["C++14"] + end + function m.completion(cfg) - _p(3, '', iif(cfg.flags["C++11"], "yes", "no"), iif(cfg.flags["C++14"], "yes", "no")) + _p(3, '', + iif(m.isCpp11(cfg), "yes", "no"), + iif(m.isCpp14(cfg), "yes", "no") + ) _p(4, '') _p(4, '') _p(4, '') -- TODO: we might want to set special code completion macros...? diff --git a/modules/codelite/tests/test_codelite_config.lua b/modules/codelite/tests/test_codelite_config.lua index 30c4f501..f17f9a78 100644 --- a/modules/codelite/tests/test_codelite_config.lua +++ b/modules/codelite/tests/test_codelite_config.lua @@ -40,7 +40,8 @@ rtti "Off" pic "On" symbols "On" - flags { "NoBufferSecurityCheck", "C++11" } + language "C++11" + flags { "NoBufferSecurityCheck" } buildoptions { "-opt1", "-opt2" } prepare() codelite.project.compiler(cfg) @@ -217,7 +218,7 @@ cmd2 end function suite.OnProject_Completion() - flags { "C++11" } + language "C++11" prepare() codelite.project.completion(prj) test.capture [[ diff --git a/modules/d/_preload.lua b/modules/d/_preload.lua index ea38663e..58c5a581 100644 --- a/modules/d/_preload.lua +++ b/modules/d/_preload.lua @@ -20,7 +20,9 @@ p.D = "D" + table.insert(p.languages.all, p.D) api.addAllowed("language", p.D) + api.addAllowed("floatingpoint", "None") api.addAllowed("flags", { "CodeCoverage", diff --git a/modules/d/actions/gmake.lua b/modules/d/actions/gmake.lua index 555e49b9..8559e8c4 100644 --- a/modules/d/actions/gmake.lua +++ b/modules/d/actions/gmake.lua @@ -239,7 +239,7 @@ if cfg.flags.SeparateCompilation then _p(' LINKCMD = $(DC) ' .. toolset.gettarget("$(TARGET)") .. ' $(ALL_LDFLAGS) $(LIBS) $(OBJECTS)') --- local cc = iif(cfg.language == "C", "CC", "CXX") +-- local cc = iif(p.languages.isc(cfg.language), "CC", "CXX") -- _p(' LINKCMD = $(%s) -o $(TARGET) $(OBJECTS) $(RESOURCES) $(ARCH) $(ALL_LDFLAGS) $(LIBS)', cc) else _p(' BUILDCMD = $(DC) ' .. toolset.gettarget("$(TARGET)") .. ' $(ALL_DFLAGS) $(ALL_LDFLAGS) $(LIBS) $(SOURCEFILES)') diff --git a/modules/xcode/xcode_common.lua b/modules/xcode/xcode_common.lua index b806d8a2..53d15d8c 100644 --- a/modules/xcode/xcode_common.lua +++ b/modules/xcode/xcode_common.lua @@ -959,6 +959,40 @@ end + function xcode.XCBuildConfiguration_CLanguageStandard(settings, cfg) + if (p.languages.isc(cfg.language)) then + if cfg.language ~= "C" then + settings['GCC_C_LANGUAGE_STANDARD'] = cfg.language:lower() + else + if cfg.flags['C99'] then + settings['GCC_C_LANGUAGE_STANDARD'] = 'C99' + elseif cfg.flags['C11'] then + settings['GCC_C_LANGUAGE_STANDARD'] = 'C11' + else + settings['GCC_C_LANGUAGE_STANDARD'] = 'C90' + end + end + else + settings['GCC_C_LANGUAGE_STANDARD'] = 'gnu99' + end + end + + + function xcode.XCBuildConfiguration_CppLanguageStandard(settings, cfg) + if (p.languages.iscpp(cfg.language)) then + if cfg.language ~= "C++" then + settings['CLANG_CXX_LANGUAGE_STANDARD'] = cfg.language:lower() + else + if cfg.flags['C++11'] then + settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'c++11' + elseif cfg.flags['C++14'] then + settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'c++14' + end + end + end + end + + function xcode.XCBuildConfiguration_Project(tr, cfg) local settings = {} @@ -987,13 +1021,8 @@ settings['COPY_PHASE_STRIP'] = 'NO' end - settings['GCC_C_LANGUAGE_STANDARD'] = 'gnu99' - - if cfg.flags['C++14'] then - settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'c++14' - elseif cfg.flags['C++11'] then - settings['CLANG_CXX_LANGUAGE_STANDARD'] = 'c++0x' - end + xcode.XCBuildConfiguration_CLanguageStandard(settings, cfg) + xcode.XCBuildConfiguration_CppLanguageStandard(settings, cfg) if cfg.exceptionhandling == p.OFF then settings['GCC_ENABLE_CPP_EXCEPTIONS'] = 'NO' diff --git a/src/_manifest.lua b/src/_manifest.lua index 6d5dc549..79ad7974 100644 --- a/src/_manifest.lua +++ b/src/_manifest.lua @@ -24,6 +24,7 @@ "base/http.lua", "base/json.lua", "base/jsonwrapper.lua", + "base/languages.lua", -- configuration data "base/field.lua", diff --git a/src/_premake_init.lua b/src/_premake_init.lua index ef9b7eaf..c88b61b9 100644 --- a/src/_premake_init.lua +++ b/src/_premake_init.lua @@ -508,11 +508,11 @@ "Unsafe", -- DEPRECATED "WinMain", "WPF", - "C++11", - "C++14", - "C90", - "C99", - "C11", + "C++11", -- DEPRECATED + "C++14", -- DEPRECATED + "C90", -- DEPRECATED + "C99", -- DEPRECATED + "C11", -- DEPRECATED }, aliases = { FatalWarnings = { "FatalWarnings", "FatalCompileWarnings", "FatalLinkWarnings" }, @@ -700,13 +700,9 @@ api.register { name = "language", - scope = "project", + scope = "config", kind = "string", - allowed = { - "C", - "C++", - "C#", - }, + allowed = p.languages.all } api.register { @@ -1374,6 +1370,13 @@ end) + -- 31 January 2017 + + api.deprecateValue("flags", "C++11", 'Use `language "C++11"` instead', function(value) end, function(value) end) + api.deprecateValue("flags", "C++14", 'Use `language "C++14"` instead', function(value) end, function(value) end) + api.deprecateValue("flags", "C90", 'Use `language "C90"` instead', function(value) end, function(value) end) + api.deprecateValue("flags", "C99", 'Use `language "C99"` instead', function(value) end, function(value) end) + api.deprecateValue("flags", "C11", 'Use `language "C11"` instead', function(value) end, function(value) end) ----------------------------------------------------------------------------- -- diff --git a/src/actions/make/_make.lua b/src/actions/make/_make.lua index 31093f7b..b1803ac4 100644 --- a/src/actions/make/_make.lua +++ b/src/actions/make/_make.lua @@ -44,7 +44,7 @@ else if project.isdotnet(prj) then premake.generate(prj, makefile, make.cs.generate) - elseif project.iscpp(prj) then + elseif project.isc(prj) or project.iscpp(prj) then premake.generate(prj, makefile, make.cpp.generate) end end diff --git a/src/actions/make/make_cpp.lua b/src/actions/make/make_cpp.lua index 24790f3e..07addc0e 100644 --- a/src/actions/make/make_cpp.lua +++ b/src/actions/make/make_cpp.lua @@ -455,7 +455,7 @@ -- $(LDFLAGS) moved to end (http://sourceforge.net/p/premake/patches/107/) -- $(LIBS) moved to end (http://sourceforge.net/p/premake/bugs/279/) - local cc = iif(cfg.language == "C", "CC", "CXX") + local cc = iif(p.languages.isc(cfg.language), "CC", "CXX") _p(' LINKCMD = $(%s) -o "$@" $(OBJECTS) $(RESOURCES) $(ALL_LDFLAGS) $(LIBS)', cc) end end diff --git a/src/actions/vstudio/_vstudio.lua b/src/actions/vstudio/_vstudio.lua index a7d3e7aa..001ee8de 100644 --- a/src/actions/vstudio/_vstudio.lua +++ b/src/actions/vstudio/_vstudio.lua @@ -456,7 +456,7 @@ local extension if project.isdotnet(prj) then extension = ".csproj" - elseif project.iscpp(prj) then + elseif project.isc(prj) or project.iscpp(prj) then extension = iif(_ACTION > "vs2008", ".vcxproj", ".vcproj") end @@ -519,11 +519,8 @@ local hasnet = false local slnarch for prj in p.workspace.eachproject(cfg.workspace) do - if project.isnative(prj) then - hasnative = true - elseif project.isdotnet(prj) then - hasnet = true - end + hasnative = hasnative or project.isnative(prj) + hasnet = hasnet or project.isdotnet(prj) -- get a VS architecture identifier for this project local prjcfg = project.getconfig(prj, cfg.buildcfg, cfg.platform) @@ -573,11 +570,8 @@ -- for prj in p.workspace.eachproject(cfg.workspace) do - if project.isnative(prj) then - hasnative = true - elseif project.isdotnet(prj) then - hasdotnet = true - end + hasnative = hasnative or project.isnative(prj) + hasnet = hasnet or project.isdotnet(prj) if hasnative and hasdotnet then return "Mixed Platforms" @@ -632,7 +626,7 @@ function vstudio.tool(prj) if project.isdotnet(prj) then return "FAE04EC0-301F-11D3-BF4B-00C04F79EFBC" - elseif project.iscpp(prj) then + elseif project.isc(prj) or project.iscpp(prj) then return "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942" end end diff --git a/src/actions/vstudio/vs2005.lua b/src/actions/vstudio/vs2005.lua index b75227fb..2a7ebc88 100644 --- a/src/actions/vstudio/vs2005.lua +++ b/src/actions/vstudio/vs2005.lua @@ -51,8 +51,7 @@ if #user > 0 then p.generate(prj, ".csproj.user", function() p.outln(user) end) end - - elseif premake.project.iscpp(prj) then + else premake.generate(prj, ".vcproj", vstudio.vc200x.generate) -- Skip generation of empty user files @@ -60,7 +59,6 @@ if #user > 0 then p.generate(prj, ".vcproj.user", function() p.outln(user) end) end - end end diff --git a/src/actions/vstudio/vs200x_vcproj.lua b/src/actions/vstudio/vs200x_vcproj.lua index e9821d60..a3dccd40 100644 --- a/src/actions/vstudio/vs200x_vcproj.lua +++ b/src/actions/vstudio/vs200x_vcproj.lua @@ -984,7 +984,7 @@ function m.compileAs(cfg, toolset) local cfg, filecfg = config.normalize(cfg) - local c = project.isc(cfg) + local c = p.languages.isc(cfg.language) if filecfg then if path.iscfile(filecfg.name) ~= c then if path.iscppfile(filecfg.name) then diff --git a/src/actions/vstudio/vs2010.lua b/src/actions/vstudio/vs2010.lua index b4fde6a6..4cd57f91 100644 --- a/src/actions/vstudio/vs2010.lua +++ b/src/actions/vstudio/vs2010.lua @@ -49,8 +49,8 @@ p.indent(" ") p.escaper(vs2010.esc) - if premake.project.isdotnet(prj) then - premake.generate(prj, ".csproj", vstudio.cs2005.generate) + if p.project.isdotnet(prj) then + p.generate(prj, ".csproj", vstudio.cs2005.generate) -- Skip generation of empty user files local user = p.capture(function() vstudio.cs2005.generateUser(prj) end) @@ -58,8 +58,8 @@ p.generate(prj, ".csproj.user", function() p.outln(user) end) end - elseif premake.project.iscpp(prj) then - premake.generate(prj, ".vcxproj", vstudio.vc2010.generate) + elseif p.project.isc(prj) or p.project.iscpp(prj) then + p.generate(prj, ".vcxproj", vstudio.vc2010.generate) -- Skip generation of empty user files local user = p.capture(function() vstudio.vc2010.generateUser(prj) end) @@ -71,7 +71,6 @@ if tree.hasbranches(project.getsourcetree(prj)) then premake.generate(prj, ".vcxproj.filters", vstudio.vc2010.generateFilters) end - end end diff --git a/src/actions/vstudio/vs2010_nuget.lua b/src/actions/vstudio/vs2010_nuget.lua index a517b483..de38fca0 100644 --- a/src/actions/vstudio/vs2010_nuget.lua +++ b/src/actions/vstudio/vs2010_nuget.lua @@ -44,13 +44,13 @@ function nuget2010.packageFramework(wks, package) local prj = packageProject(wks, package) - if p.project.iscpp(prj) then - return "native" - elseif p.project.isdotnet(prj) then + if p.project.isdotnet(prj) then local cfg = p.project.getfirstconfig(prj) local action = premake.action.current() local framework = cfg.dotnetframework or action.vstudio.targetFramework return cs2005.formatNuGetFrameworkVersion(framework) + else + return "native" end end diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index c4be0603..bf98ff61 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -1,1268 +1,1268 @@ --- --- vs2010_vcxproj.lua --- Generate a Visual Studio 201x C/C++ project. --- Copyright (c) 2009-2015 Jason Perkins and the Premake project --- - - premake.vstudio.vc2010 = {} - - local p = premake - local vstudio = p.vstudio - local project = p.project - local config = p.config - local fileconfig = p.fileconfig - local tree = p.tree - - local m = p.vstudio.vc2010 - - ---- --- Add namespace for element definition lists for premake.callArray() ---- - - m.elements = {} - - --- --- Generate a Visual Studio 201x C++ project, with support for the new platforms API. --- - - m.elements.project = function(prj) - return { - m.xmlDeclaration, - m.project, - m.projectConfigurations, - m.globals, - m.importDefaultProps, - m.configurationPropertiesGroup, - m.importLanguageSettings, - m.importExtensionSettings, - m.propertySheetGroup, - m.userMacros, - m.outputPropertiesGroup, - m.itemDefinitionGroups, - m.assemblyReferences, - m.files, - m.projectReferences, - m.importLanguageTargets, - m.importExtensionTargets, - m.ensureNuGetPackageBuildImports, - } - end - - function m.generate(prj) - p.utf8() - p.callArray(m.elements.project, prj) - p.out('') - end - - --- --- Output the XML declaration and opening tag. --- - - function m.project(prj) - local action = p.action.current() - p.push('', - action.vstudio.toolsVersion) - end - - --- --- Write out the list of project configurations, which pairs build --- configurations with architectures. --- - - function m.projectConfigurations(prj) - - -- build a list of all architectures used in this project - local platforms = {} - for cfg in project.eachconfig(prj) do - local arch = vstudio.archFromConfig(cfg, true) - if not table.contains(platforms, arch) then - table.insert(platforms, arch) - end - end - - local configs = {} - p.push('') - for cfg in project.eachconfig(prj) do - for _, arch in ipairs(platforms) do - local prjcfg = vstudio.projectConfig(cfg, arch) - if not configs[prjcfg] then - configs[prjcfg] = prjcfg - p.push('', vstudio.projectConfig(cfg, arch)) - p.x('%s', vstudio.projectPlatform(cfg)) - p.w('%s', arch) - p.pop('') - end - end - end - p.pop('') - end - - --- --- Write out the TargetFrameworkVersion property. --- - - function m.targetFramework(prj) - local action = p.action.current() - local tools = string.format(' ToolsVersion="%s"', action.vstudio.toolsVersion) - - local framework = prj.dotnetframework or action.vstudio.targetFramework or "4.0" - p.w('v%s', framework) - end - - - --- --- Write out the Globals property group. --- - - m.elements.globals = function(prj) - return { - m.projectGuid, - m.ignoreWarnDuplicateFilename, - m.keyword, - m.projectName, - m.targetPlatformVersion, - } - end - - function m.globals(prj) - m.propertyGroup(nil, "Globals") - p.callArray(m.elements.globals, prj) - p.pop('') - end - - --- --- Write out the configuration property group: what kind of binary it --- produces, and some global settings. --- - - m.elements.configurationProperties = function(cfg) - if cfg.kind == p.UTILITY then - return { - m.configurationType, - m.platformToolset, - } - else - return { - m.configurationType, - m.useDebugLibraries, - m.useOfMfc, - m.useOfAtl, - m.clrSupport, - m.characterSet, - m.platformToolset, - m.wholeProgramOptimization, - m.nmakeOutDirs, - } - end - end - - function m.configurationProperties(cfg) - m.propertyGroup(cfg, "Configuration") - p.callArray(m.elements.configurationProperties, cfg) - p.pop('') - end - - function m.configurationPropertiesGroup(prj) - for cfg in project.eachconfig(prj) do - m.configurationProperties(cfg) - end - end - - - --- --- Write the output property group, which includes the output and intermediate --- directories, manifest, etc. --- - - m.elements.outputProperties = function(cfg) - if cfg.kind == p.UTILITY then - return { - m.outDir, - m.intDir, - m.extensionsToDeleteOnClean, - } - else - return { - m.linkIncremental, - m.ignoreImportLibrary, - m.outDir, - m.outputFile, - m.intDir, - m.targetName, - m.targetExt, - m.includePath, - m.libraryPath, - m.imageXexOutput, - m.generateManifest, - m.extensionsToDeleteOnClean, - m.executablePath, - } - end - end - - function m.outputProperties(cfg) - if not vstudio.isMakefile(cfg) then - m.propertyGroup(cfg) - p.callArray(m.elements.outputProperties, cfg) - p.pop('') - end - end - - --- --- Write the NMake property group for Makefile projects, which includes the custom --- build commands, output file location, etc. --- - - m.elements.nmakeProperties = function(cfg) - return { - m.nmakeOutput, - m.nmakeBuildCommands, - m.nmakeRebuildCommands, - m.nmakeCleanCommands, - m.nmakePreprocessorDefinitions, - m.nmakeIncludeDirs - } - end - - function m.nmakeProperties(cfg) - if vstudio.isMakefile(cfg) then - m.propertyGroup(cfg) - p.callArray(m.elements.nmakeProperties, cfg) - p.pop('') - end - end - - --- --- Output properties and NMake properties should appear side-by-side --- for each configuration. --- - - function m.outputPropertiesGroup(prj) - for cfg in project.eachconfig(prj) do - m.outputProperties(cfg) - m.nmakeProperties(cfg) - end - end - - - --- --- Write a configuration's item definition group, which contains all --- of the per-configuration compile and link settings. --- - - m.elements.itemDefinitionGroup = function(cfg) - if cfg.kind == p.UTILITY then - return { - m.ruleVars, - m.buildEvents, - } - else - return { - m.clCompile, - m.resourceCompile, - m.linker, - m.manifest, - m.buildEvents, - m.imageXex, - m.deploy, - m.ruleVars, - m.buildLog, - } - end - end - - function m.itemDefinitionGroup(cfg) - if not vstudio.isMakefile(cfg) then - p.push('', m.condition(cfg)) - p.callArray(m.elements.itemDefinitionGroup, cfg) - p.pop('') - - else - if cfg == project.getfirstconfig(cfg.project) then - p.w('') - p.w('') - end - end - end - - function m.itemDefinitionGroups(prj) - for cfg in project.eachconfig(prj) do - m.itemDefinitionGroup(cfg) - end - end - - - --- --- Write the the compiler settings block. --- - - m.elements.clCompile = function(cfg) - return { - m.precompiledHeader, - m.warningLevel, - m.treatWarningAsError, - m.disableSpecificWarnings, - m.treatSpecificWarningsAsErrors, - m.basicRuntimeChecks, - m.clCompilePreprocessorDefinitions, - m.clCompileUndefinePreprocessorDefinitions, - m.clCompileAdditionalIncludeDirectories, - m.clCompileAdditionalUsingDirectories, - m.forceIncludes, - m.debugInformationFormat, - m.optimization, - m.functionLevelLinking, - m.intrinsicFunctions, - m.minimalRebuild, - m.omitFramePointers, - m.stringPooling, - m.runtimeLibrary, - m.omitDefaultLib, - m.exceptionHandling, - m.runtimeTypeInfo, - m.bufferSecurityCheck, - m.treatWChar_tAsBuiltInType, - m.floatingPointModel, - m.floatingPointExceptions, - m.inlineFunctionExpansion, - m.enableEnhancedInstructionSet, - m.multiProcessorCompilation, - m.additionalCompileOptions, - m.compileAs, - m.callingConvention, - } - end - - function m.clCompile(cfg) - p.push('') - p.callArray(m.elements.clCompile, cfg) - p.pop('') - end - - --- --- Write out the resource compiler block. --- - - m.elements.resourceCompile = function(cfg) - return { - m.resourcePreprocessorDefinitions, - m.resourceAdditionalIncludeDirectories, - m.culture, - } - end - - function m.resourceCompile(cfg) - if cfg.system ~= p.XBOX360 and p.config.hasFile(cfg, path.isresourcefile) then - local contents = p.capture(function () - p.push() - p.callArray(m.elements.resourceCompile, cfg) - p.pop() - end) - - if #contents > 0 then - p.push('') - p.outln(contents) - p.pop('') - end - end - end - - --- --- Write out the linker tool block. --- - - m.elements.linker = function(cfg, explicit) - return { - m.link, - m.lib, - m.linkLibraryDependencies, - } - end - - function m.linker(cfg) - local explicit = vstudio.needsExplicitLink(cfg) - p.callArray(m.elements.linker, cfg, explicit) - end - - - - m.elements.link = function(cfg, explicit) - if cfg.kind == p.STATICLIB then - return { - m.subSystem, - m.fullProgramDatabaseFile, - m.generateDebugInformation, - m.optimizeReferences, - } - else - return { - m.subSystem, - m.fullProgramDatabaseFile, - m.generateDebugInformation, - m.optimizeReferences, - m.additionalDependencies, - m.additionalLibraryDirectories, - m.importLibrary, - m.entryPointSymbol, - m.generateMapFile, - m.moduleDefinitionFile, - m.treatLinkerWarningAsErrors, - m.ignoreDefaultLibraries, - m.largeAddressAware, - m.targetMachine, - m.additionalLinkOptions, - m.programDatabaseFile, - } - end - end - - function m.link(cfg, explicit) - local contents = p.capture(function () - p.push() - p.callArray(m.elements.link, cfg, explicit) - p.pop() - end) - if #contents > 0 then - p.push('') - p.outln(contents) - p.pop('') - end - end - - - - m.elements.lib = function(cfg, explicit) - if cfg.kind == p.STATICLIB then - return { - m.additionalDependencies, - m.additionalLibraryDirectories, - m.treatLinkerWarningAsErrors, - m.targetMachine, - m.additionalLinkOptions, - } - else - return {} - end - end - - function m.lib(cfg, explicit) - local contents = p.capture(function () - p.push() - p.callArray(m.elements.lib, cfg, explicit) - p.pop() - end) - if #contents > 0 then - p.push('') - p.outln(contents) - p.pop('') - end - end - - - --- --- Write the manifest section. --- - - function m.manifest(cfg) - if cfg.kind ~= p.STATICLIB then - -- get the manifests files - local manifests = {} - for _, fname in ipairs(cfg.files) do - if path.getextension(fname) == ".manifest" then - table.insert(manifests, project.getrelative(cfg.project, fname)) - end - end - - if #manifests > 0 then - p.push('') - m.element("AdditionalManifestFiles", nil, "%s %%(AdditionalManifestFiles)", table.concat(manifests, " ")) - p.pop('') - end - end - end - - - ---- --- Write out the pre- and post-build event settings. ---- - - function m.buildEvents(cfg) - local write = function (event) - local name = event .. "Event" - local field = event:lower() - local steps = cfg[field .. "commands"] - local msg = cfg[field .. "message"] - - if #steps > 0 then - steps = os.translateCommands(steps, p.WINDOWS) - p.push('<%s>', name) - p.x('%s', table.implode(steps, "", "", "\r\n")) - if msg then - p.x('%s', msg) - end - p.pop('', name) - end - end - - write("PreBuild") - write("PreLink") - write("PostBuild") - end - - - ---- --- Write out project-level custom rule variables. ---- - - function m.ruleVars(cfg) - for i = 1, #cfg.rules do - local rule = p.global.getRule(cfg.rules[i]) - - local contents = p.capture(function () - p.push() - for prop in p.rule.eachProperty(rule) do - local fld = p.rule.getPropertyField(rule, prop) - local value = cfg[fld.name] - if value ~= nil then - if fld.kind == "list:path" then - value = table.concat(vstudio.path(cfg, value), ';') - elseif fld.kind == "path" then - value = vstudio.path(cfg, value) - else - value = p.rule.getPropertyString(rule, prop, value) - end - - if value ~= nil and #value > 0 then - m.element(prop.name, nil, '%s', value) - end - end - end - p.pop() - end) - - if #contents > 0 then - p.push('<%s>', rule.name) - p.outln(contents) - p.pop('', rule.name) - end - end - end - - --- --- Reference any managed assemblies listed in the links() --- - - function m.assemblyReferences(prj) - -- Visual Studio doesn't support per-config references; use - -- whatever is contained in the first configuration - local cfg = project.getfirstconfig(prj) - - local refs = config.getlinks(cfg, "system", "fullpath", "managed") - if #refs > 0 then - p.push('') - for i = 1, #refs do - local value = refs[i] - - -- If the link contains a '/' then it is a relative path to - -- a local assembly. Otherwise treat it as a system assembly. - if value:find('/', 1, true) then - p.push('', path.getbasename(value)) - p.x('%s', path.translate(value)) - p.pop('') - else - p.x('', path.getbasename(value)) - end - end - p.pop('') - end - end - - - function m.generatedFile(cfg, file) - if file.generated then - local path = path.translate(file.dependsOn.relpath) - m.element("AutoGen", nil, 'true') - m.element("DependentUpon", nil, path) - end - end - - ---- --- Write out the list of source code files, and any associated configuration. ---- - - function m.files(prj) - local groups = m.categorizeSources(prj) - for _, group in ipairs(groups) do - group.category.emitFiles(prj, group) - end - end - - - m.categories = {} - ---- --- ClInclude group ---- - m.categories.ClInclude = { - name = "ClInclude", - extensions = { ".h", ".hh", ".hpp", ".hxx", ".inl" }, - priority = 1, - - emitFiles = function(prj, group) - m.emitFiles(prj, group, "ClInclude", {m.generatedFile}) - end, - - emitFilter = function(prj, group) - m.filterGroup(prj, group, "ClInclude") - end - } - - ---- --- ClCompile group ---- - m.categories.ClCompile = { - name = "ClCompile", - extensions = { ".cc", ".cpp", ".cxx", ".c", ".s", ".m", ".mm" }, - priority = 2, - - emitFiles = function(prj, group) - local fileCfgFunc = function(fcfg, condition) - if fcfg then - return { - m.excludedFromBuild, - m.objectFileName, - m.clCompilePreprocessorDefinitions, - m.clCompileUndefinePreprocessorDefinitions, - m.optimization, - m.forceIncludes, - m.precompiledHeader, - m.enableEnhancedInstructionSet, - m.additionalCompileOptions, - m.disableSpecificWarnings, - m.treatSpecificWarningsAsErrors, - m.basicRuntimeChecks, - m.exceptionHandling, - m.compileAsManaged, - } - else - return { - m.excludedFromBuild - } - end - end - - m.emitFiles(prj, group, "ClCompile", {m.generatedFile}, fileCfgFunc) - end, - - emitFilter = function(prj, group) - m.filterGroup(prj, group, "ClCompile") - end - } - - ---- --- None group ---- - m.categories.None = { - name = "None", - priority = 3, - - emitFiles = function(prj, group) - m.emitFiles(prj, group, "None", {m.generatedFile}) - end, - - emitFilter = function(prj, group) - m.filterGroup(prj, group, "None") - end - } - - ---- --- ResourceCompile group ---- - m.categories.ResourceCompile = { - name = "ResourceCompile", - extensions = ".rc", - priority = 4, - - emitFiles = function(prj, group) - local fileCfgFunc = { - m.excludedFromBuild - } - - m.emitFiles(prj, group, "ResourceCompile", nil, fileCfgFunc, function(cfg) - return cfg.system == p.WINDOWS - end) - end, - - emitFilter = function(prj, group) - m.filterGroup(prj, group, "ResourceCompile") - end - } - - ---- --- CustomBuild group ---- - m.categories.CustomBuild = { - name = "CustomBuild", - priority = 5, - - emitFiles = function(prj, group) - local fileFunc = { - m.fileType - } - - local fileCfgFunc = { - m.excludedFromBuild, - m.buildCommands, - m.buildOutputs, - m.linkObjects, - m.buildMessage, - m.buildAdditionalInputs - } - - m.emitFiles(prj, group, "CustomBuild", fileFunc, fileCfgFunc, function (cfg, fcfg) - return fileconfig.hasCustomBuildRule(fcfg) - end) - end, - - emitFilter = function(prj, group) - m.filterGroup(prj, group, "CustomBuild") - end - } - - ---- --- Midl group ---- - m.categories.Midl = { - name = "Midl", - extensions = ".idl", - priority = 6, - - emitFiles = function(prj, group) - local fileCfgFunc = { - m.excludedFromBuild - } - - m.emitFiles(prj, group, "Midl", nil, fileCfgFunc, function(cfg) - return cfg.system == p.WINDOWS - end) - end, - - emitFilter = function(prj, group) - m.filterGroup(prj, group, "Midl") - end - } - ---- --- Masm group ---- - m.categories.Masm = { - name = "Masm", - extensions = ".asm", - priority = 7, - - emitFiles = function(prj, group) - local fileCfgFunc = { - m.excludedFromBuild - } - - m.emitFiles(prj, group, "Masm", nil, fileCfgFunc, function(cfg) - return cfg.system == p.WINDOWS - end) - end, - - emitFilter = function(prj, group) - m.filterGroup(prj, group, "Masm") - end, - - emitExtensionSettings = function(prj, group) - p.w('') - end, - - emitExtensionTargets = function(prj, group) - p.w('') - end - } - - ---- --- Categorize files into groups. ---- - function m.categorizeSources(prj) - -- if we already did this, return the cached result. - if prj._vc2010_sources then - return prj._vc2010_sources - end - - -- build the new group table. - local result = {} - local groups = {} - prj._vc2010_sources = result - - local tr = project.getsourcetree(prj) - tree.traverse(tr, { - onleaf = function(node) - local cat = m.categorizeFile(prj, node) - groups[cat.name] = groups[cat.name] or { - category = cat, - files = {} - } - table.insert(groups[cat.name].files, node) - end - }) - - -- sort by relative-to path; otherwise VS will reorder the files - for name, group in pairs(groups) do - table.sort(group.files, function (a, b) - return a.relpath < b.relpath - end) - table.insert(result, group) - end - - -- sort by category priority then name; so we get stable results. - table.sort(result, function (a, b) - if (a.category.priority == b.category.priority) then - return a.category.name < b.category.name - end - return a.category.priority < b.category.priority - end) - - return result - end - - - function m.categorizeFile(prj, file) - -- If any configuration for this file uses a custom build step, - -- that's the category to use - for cfg in project.eachconfig(prj) do - local fcfg = fileconfig.getconfig(file, cfg) - if fileconfig.hasCustomBuildRule(fcfg) then - return m.categories.CustomBuild - end - end - - -- If there is a custom rule associated with it, use that - local rule = p.global.getRuleForFile(file.name, prj.rules) - if rule then - return { - name = rule.name, - priority = 100, - rule = rule, - emitFiles = function(prj, group) - m.emitRuleFiles(prj, group) - end, - emitFilter = function(prj, group) - m.filterGroup(prj, group, group.category.name) - end - } - end - - -- Otherwise use the file extension to deduce a category - for _, cat in pairs(m.categories) do - if cat.extensions and path.hasextension(file.name, cat.extensions) then - return cat - end - end - - return m.categories.None - end - - - function m.emitFiles(prj, group, tag, fileFunc, fileCfgFunc, checkFunc) - local files = group.files - if files and #files > 0 then - p.push('') - for _, file in ipairs(files) do - - local contents = p.capture(function () - p.push() - p.callArray(fileFunc, cfg, file) - for cfg in project.eachconfig(prj) do - local fcfg = fileconfig.getconfig(file, cfg) - if not checkFunc or checkFunc(cfg, fcfg) then - p.callArray(fileCfgFunc, fcfg, m.condition(cfg)) - end - end - p.pop() - end) - - local rel = path.translate(file.relpath) - if #contents > 0 then - p.push('<%s Include="%s">', tag, rel) - p.outln(contents) - p.pop('', tag) - else - p.x('<%s Include="%s" />', tag, rel) - end - - end - p.pop('') - end - end - - function m.emitRuleFiles(prj, group) - local files = group.files - local rule = group.category.rule - - if files and #files > 0 then - p.push('') - - for _, file in ipairs(files) do - local contents = p.capture(function() - p.push() - for prop in p.rule.eachProperty(rule) do - local fld = p.rule.getPropertyField(rule, prop) - - for cfg in project.eachconfig(prj) do - local fcfg = fileconfig.getconfig(file, cfg) - if fcfg and fcfg[fld.name] then - local value = p.rule.getPropertyString(rule, prop, fcfg[fld.name]) - if value and #value > 0 then - m.element(prop.name, m.condition(cfg), '%s', value) - end - end - end - - end - p.pop() - end) - - if #contents > 0 then - p.push('<%s Include=\"%s\">', rule.name, path.translate(file.relpath)) - p.outln(contents) - p.pop('', rule.name) - else - p.x('<%s Include=\"%s\" />', rule.name, path.translate(file.relpath)) - end - end - - p.pop('') - end - end - - - function m.isClrMixed(prj) - -- check to see if any files are marked with clr - local isMixed = false - if not prj.clr or prj.clr == p.OFF then - if prj._isClrMixed ~= nil then - isMixed = prj._isClrMixed - else - table.foreachi(prj._.files, function(file) - for cfg in p.project.eachconfig(prj) do - local fcfg = p.fileconfig.getconfig(file, cfg) - if fcfg and fcfg.clr and fcfg.clr ~= p.OFF then - isMixed = true - end - end - end) - prj._isClrMixed = isMixed -- cache the results - end - end - return isMixed - end - - --- --- Generate the list of project dependencies. --- - - m.elements.projectReferences = function(prj, ref) - if prj.clr ~= p.OFF or (m.isClrMixed(prj) and ref and ref.kind ~=p.STATICLIB) then - return { - m.referenceProject, - m.referencePrivate, - m.referenceOutputAssembly, - m.referenceCopyLocalSatelliteAssemblies, - m.referenceLinkLibraryDependencies, - m.referenceUseLibraryDependences, - } - else - return { - m.referenceProject, - } - end - end - - function m.projectReferences(prj) - local refs = project.getdependencies(prj, 'linkOnly') - if #refs > 0 then - p.push('') - for _, ref in ipairs(refs) do - local relpath = vstudio.path(prj, vstudio.projectfile(ref)) - p.push('', relpath) - p.callArray(m.elements.projectReferences, prj, ref) - p.pop('') - end - p.pop('') - end - end - - - ---------------------------------------------------------------------------- --- --- Handlers for individual project elements --- ---------------------------------------------------------------------------- - - function m.additionalDependencies(cfg, explicit) - local links - - -- check to see if this project uses an external toolset. If so, let the - -- toolset define the format of the links - local toolset = config.toolset(cfg) - if toolset then - links = toolset.getlinks(cfg, not explicit) - else - links = vstudio.getLinks(cfg, explicit) - end - - if #links > 0 then - links = path.translate(table.concat(links, ";")) - m.element("AdditionalDependencies", nil, "%s;%%(AdditionalDependencies)", links) - end - end - - - function m.additionalIncludeDirectories(cfg, includedirs) - if #includedirs > 0 then - local dirs = vstudio.path(cfg, includedirs) - if #dirs > 0 then - m.element("AdditionalIncludeDirectories", nil, "%s;%%(AdditionalIncludeDirectories)", table.concat(dirs, ";")) - end - end - end - - - function m.additionalLibraryDirectories(cfg) - if #cfg.libdirs > 0 then - local dirs = table.concat(vstudio.path(cfg, cfg.libdirs), ";") - m.element("AdditionalLibraryDirectories", nil, "%s;%%(AdditionalLibraryDirectories)", dirs) - end - end - - - function m.additionalUsingDirectories(cfg) - if #cfg.usingdirs > 0 then - local dirs = vstudio.path(cfg, cfg.usingdirs) - if #dirs > 0 then - m.element("AdditionalUsingDirectories", nil, "%s;%%(AdditionalUsingDirectories)", table.concat(dirs, ";")) - end - end - end - - - function m.largeAddressAware(cfg) - if (cfg.largeaddressaware == true) then - m.element("LargeAddressAware", nil, 'true') - end - end - - - function m.additionalCompileOptions(cfg, condition) - if #cfg.buildoptions > 0 then - local opts = table.concat(cfg.buildoptions, " ") - m.element("AdditionalOptions", condition, '%s %%(AdditionalOptions)', opts) - end - end - - - function m.additionalLinkOptions(cfg) - if #cfg.linkoptions > 0 then - local opts = table.concat(cfg.linkoptions, " ") - m.element("AdditionalOptions", nil, "%s %%(AdditionalOptions)", opts) - end - end - - - function m.compileAsManaged(fcfg, condition) - if fcfg.clr and fcfg ~= p.OFF then - m.element("CompileAsManaged", condition, "true") - end - end - - - function m.basicRuntimeChecks(cfg, condition) - local prjcfg, filecfg = p.config.normalize(cfg) - local runtime = config.getruntime(prjcfg) - if filecfg then - if filecfg.flags.NoRuntimeChecks or (config.isOptimizedBuild(filecfg) and runtime:endswith("Debug")) then - m.element("BasicRuntimeChecks", condition, "Default") - end - else - if prjcfg.flags.NoRuntimeChecks or (config.isOptimizedBuild(prjcfg) and runtime:endswith("Debug")) then - m.element("BasicRuntimeChecks", nil, "Default") - end - end - end - - - function m.buildAdditionalInputs(fcfg, condition) - if fcfg.buildinputs and #fcfg.buildinputs > 0 then - local inputs = project.getrelative(fcfg.project, fcfg.buildinputs) - m.element("AdditionalInputs", condition, '%s', table.concat(inputs, ";")) - end - end - - - function m.buildCommands(fcfg, condition) - local commands = os.translateCommands(fcfg.buildcommands, p.WINDOWS) - commands = table.concat(commands,'\r\n') - m.element("Command", condition, '%s', commands) - end - - - function m.buildLog(cfg) - if cfg.buildlog and #cfg.buildlog > 0 then - p.push('') - m.element("Path", nil, "%s", vstudio.path(cfg, cfg.buildlog)) - p.pop('') - end - end - - - function m.buildMessage(fcfg, condition) - if fcfg.buildmessage then - m.element("Message", condition, '%s', fcfg.buildmessage) - end - end - - - function m.buildOutputs(fcfg, condition) - local outputs = project.getrelative(fcfg.project, fcfg.buildoutputs) - m.element("Outputs", condition, '%s', table.concat(outputs, ";")) - end - - - function m.linkObjects(fcfg, condition) - if fcfg.linkbuildoutputs ~= nil then - m.element("LinkObjects", condition, tostring(fcfg.linkbuildoutputs)) - end - end - - - function m.characterSet(cfg) - if not vstudio.isMakefile(cfg) then - m.element("CharacterSet", nil, iif(cfg.characterset == p.MBCS, "MultiByte", "Unicode")) - end - end - - - function m.wholeProgramOptimization(cfg) - if cfg.flags.LinkTimeOptimization then - m.element("WholeProgramOptimization", nil, "true") - end - end - - function m.clCompileAdditionalIncludeDirectories(cfg) - m.additionalIncludeDirectories(cfg, cfg.includedirs) - end - - function m.clCompileAdditionalUsingDirectories(cfg) - m.additionalUsingDirectories(cfg, cfg.usingdirs) - end - - - function m.clCompilePreprocessorDefinitions(cfg, condition) - local defines = cfg.defines - if cfg.exceptionhandling == p.OFF and _ACTION >= "vs2013" then - defines = table.join(defines, "_HAS_EXCEPTIONS=0") - end - m.preprocessorDefinitions(cfg, defines, false, condition) - end - - - function m.clCompileUndefinePreprocessorDefinitions(cfg, condition) - m.undefinePreprocessorDefinitions(cfg, cfg.undefines, false, condition) - end - - - function m.clrSupport(cfg) - local value - if cfg.clr == "On" or cfg.clr == "Unsafe" then - value = "true" - elseif cfg.clr ~= p.OFF then - value = cfg.clr - end - if value then - m.element("CLRSupport", nil, value) - end - end - - - function m.compileAs(cfg) - if cfg.project.language == "C" then - m.element("CompileAs", nil, "CompileAsC") - end - end - - - function m.configurationType(cfg) - local types = { - SharedLib = "DynamicLibrary", - StaticLib = "StaticLibrary", - ConsoleApp = "Application", - WindowedApp = "Application", - Makefile = "Makefile", - None = "Makefile", - Utility = "Utility", - } - m.element("ConfigurationType", nil, types[cfg.kind]) - end - - - function m.culture(cfg) - local value = vstudio.cultureForLocale(cfg.locale) - if value then - m.element("Culture", nil, "0x%04x", tostring(value)) - end - end - - - function m.debugInformationFormat(cfg) - local value - local tool, toolVersion = p.config.toolset(cfg) - if (cfg.symbols == p.ON) or (cfg.symbols == "FastLink") then - if cfg.debugformat == "c7" then - value = "OldStyle" - elseif (cfg.architecture == "x86_64" and _ACTION < "vs2015") or - cfg.clr ~= p.OFF or - config.isOptimizedBuild(cfg) or - cfg.editandcontinue == p.OFF or - (toolVersion and toolVersion:startswith("LLVM-vs")) - then - value = "ProgramDatabase" - else - value = "EditAndContinue" - end - - m.element("DebugInformationFormat", nil, value) - elseif cfg.symbols == p.OFF then - -- leave field blank for vs2013 and older to workaround bug +-- +-- vs2010_vcxproj.lua +-- Generate a Visual Studio 201x C/C++ project. +-- Copyright (c) 2009-2015 Jason Perkins and the Premake project +-- + + premake.vstudio.vc2010 = {} + + local p = premake + local vstudio = p.vstudio + local project = p.project + local config = p.config + local fileconfig = p.fileconfig + local tree = p.tree + + local m = p.vstudio.vc2010 + + +--- +-- Add namespace for element definition lists for premake.callArray() +--- + + m.elements = {} + + +-- +-- Generate a Visual Studio 201x C++ project, with support for the new platforms API. +-- + + m.elements.project = function(prj) + return { + m.xmlDeclaration, + m.project, + m.projectConfigurations, + m.globals, + m.importDefaultProps, + m.configurationPropertiesGroup, + m.importLanguageSettings, + m.importExtensionSettings, + m.propertySheetGroup, + m.userMacros, + m.outputPropertiesGroup, + m.itemDefinitionGroups, + m.assemblyReferences, + m.files, + m.projectReferences, + m.importLanguageTargets, + m.importExtensionTargets, + m.ensureNuGetPackageBuildImports, + } + end + + function m.generate(prj) + p.utf8() + p.callArray(m.elements.project, prj) + p.out('') + end + + +-- +-- Output the XML declaration and opening tag. +-- + + function m.project(prj) + local action = p.action.current() + p.push('', + action.vstudio.toolsVersion) + end + + +-- +-- Write out the list of project configurations, which pairs build +-- configurations with architectures. +-- + + function m.projectConfigurations(prj) + + -- build a list of all architectures used in this project + local platforms = {} + for cfg in project.eachconfig(prj) do + local arch = vstudio.archFromConfig(cfg, true) + if not table.contains(platforms, arch) then + table.insert(platforms, arch) + end + end + + local configs = {} + p.push('') + for cfg in project.eachconfig(prj) do + for _, arch in ipairs(platforms) do + local prjcfg = vstudio.projectConfig(cfg, arch) + if not configs[prjcfg] then + configs[prjcfg] = prjcfg + p.push('', vstudio.projectConfig(cfg, arch)) + p.x('%s', vstudio.projectPlatform(cfg)) + p.w('%s', arch) + p.pop('') + end + end + end + p.pop('') + end + + +-- +-- Write out the TargetFrameworkVersion property. +-- + + function m.targetFramework(prj) + local action = p.action.current() + local tools = string.format(' ToolsVersion="%s"', action.vstudio.toolsVersion) + + local framework = prj.dotnetframework or action.vstudio.targetFramework or "4.0" + p.w('v%s', framework) + end + + + +-- +-- Write out the Globals property group. +-- + + m.elements.globals = function(prj) + return { + m.projectGuid, + m.ignoreWarnDuplicateFilename, + m.keyword, + m.projectName, + m.targetPlatformVersion, + } + end + + function m.globals(prj) + m.propertyGroup(nil, "Globals") + p.callArray(m.elements.globals, prj) + p.pop('') + end + + +-- +-- Write out the configuration property group: what kind of binary it +-- produces, and some global settings. +-- + + m.elements.configurationProperties = function(cfg) + if cfg.kind == p.UTILITY then + return { + m.configurationType, + m.platformToolset, + } + else + return { + m.configurationType, + m.useDebugLibraries, + m.useOfMfc, + m.useOfAtl, + m.clrSupport, + m.characterSet, + m.platformToolset, + m.wholeProgramOptimization, + m.nmakeOutDirs, + } + end + end + + function m.configurationProperties(cfg) + m.propertyGroup(cfg, "Configuration") + p.callArray(m.elements.configurationProperties, cfg) + p.pop('') + end + + function m.configurationPropertiesGroup(prj) + for cfg in project.eachconfig(prj) do + m.configurationProperties(cfg) + end + end + + + +-- +-- Write the output property group, which includes the output and intermediate +-- directories, manifest, etc. +-- + + m.elements.outputProperties = function(cfg) + if cfg.kind == p.UTILITY then + return { + m.outDir, + m.intDir, + m.extensionsToDeleteOnClean, + } + else + return { + m.linkIncremental, + m.ignoreImportLibrary, + m.outDir, + m.outputFile, + m.intDir, + m.targetName, + m.targetExt, + m.includePath, + m.libraryPath, + m.imageXexOutput, + m.generateManifest, + m.extensionsToDeleteOnClean, + m.executablePath, + } + end + end + + function m.outputProperties(cfg) + if not vstudio.isMakefile(cfg) then + m.propertyGroup(cfg) + p.callArray(m.elements.outputProperties, cfg) + p.pop('') + end + end + + +-- +-- Write the NMake property group for Makefile projects, which includes the custom +-- build commands, output file location, etc. +-- + + m.elements.nmakeProperties = function(cfg) + return { + m.nmakeOutput, + m.nmakeBuildCommands, + m.nmakeRebuildCommands, + m.nmakeCleanCommands, + m.nmakePreprocessorDefinitions, + m.nmakeIncludeDirs + } + end + + function m.nmakeProperties(cfg) + if vstudio.isMakefile(cfg) then + m.propertyGroup(cfg) + p.callArray(m.elements.nmakeProperties, cfg) + p.pop('') + end + end + + +-- +-- Output properties and NMake properties should appear side-by-side +-- for each configuration. +-- + + function m.outputPropertiesGroup(prj) + for cfg in project.eachconfig(prj) do + m.outputProperties(cfg) + m.nmakeProperties(cfg) + end + end + + + +-- +-- Write a configuration's item definition group, which contains all +-- of the per-configuration compile and link settings. +-- + + m.elements.itemDefinitionGroup = function(cfg) + if cfg.kind == p.UTILITY then + return { + m.ruleVars, + m.buildEvents, + } + else + return { + m.clCompile, + m.resourceCompile, + m.linker, + m.manifest, + m.buildEvents, + m.imageXex, + m.deploy, + m.ruleVars, + m.buildLog, + } + end + end + + function m.itemDefinitionGroup(cfg) + if not vstudio.isMakefile(cfg) then + p.push('', m.condition(cfg)) + p.callArray(m.elements.itemDefinitionGroup, cfg) + p.pop('') + + else + if cfg == project.getfirstconfig(cfg.project) then + p.w('') + p.w('') + end + end + end + + function m.itemDefinitionGroups(prj) + for cfg in project.eachconfig(prj) do + m.itemDefinitionGroup(cfg) + end + end + + + +-- +-- Write the the compiler settings block. +-- + + m.elements.clCompile = function(cfg) + return { + m.precompiledHeader, + m.warningLevel, + m.treatWarningAsError, + m.disableSpecificWarnings, + m.treatSpecificWarningsAsErrors, + m.basicRuntimeChecks, + m.clCompilePreprocessorDefinitions, + m.clCompileUndefinePreprocessorDefinitions, + m.clCompileAdditionalIncludeDirectories, + m.clCompileAdditionalUsingDirectories, + m.forceIncludes, + m.debugInformationFormat, + m.optimization, + m.functionLevelLinking, + m.intrinsicFunctions, + m.minimalRebuild, + m.omitFramePointers, + m.stringPooling, + m.runtimeLibrary, + m.omitDefaultLib, + m.exceptionHandling, + m.runtimeTypeInfo, + m.bufferSecurityCheck, + m.treatWChar_tAsBuiltInType, + m.floatingPointModel, + m.floatingPointExceptions, + m.inlineFunctionExpansion, + m.enableEnhancedInstructionSet, + m.multiProcessorCompilation, + m.additionalCompileOptions, + m.compileAs, + m.callingConvention, + } + end + + function m.clCompile(cfg) + p.push('') + p.callArray(m.elements.clCompile, cfg) + p.pop('') + end + + +-- +-- Write out the resource compiler block. +-- + + m.elements.resourceCompile = function(cfg) + return { + m.resourcePreprocessorDefinitions, + m.resourceAdditionalIncludeDirectories, + m.culture, + } + end + + function m.resourceCompile(cfg) + if cfg.system ~= p.XBOX360 and p.config.hasFile(cfg, path.isresourcefile) then + local contents = p.capture(function () + p.push() + p.callArray(m.elements.resourceCompile, cfg) + p.pop() + end) + + if #contents > 0 then + p.push('') + p.outln(contents) + p.pop('') + end + end + end + + +-- +-- Write out the linker tool block. +-- + + m.elements.linker = function(cfg, explicit) + return { + m.link, + m.lib, + m.linkLibraryDependencies, + } + end + + function m.linker(cfg) + local explicit = vstudio.needsExplicitLink(cfg) + p.callArray(m.elements.linker, cfg, explicit) + end + + + + m.elements.link = function(cfg, explicit) + if cfg.kind == p.STATICLIB then + return { + m.subSystem, + m.fullProgramDatabaseFile, + m.generateDebugInformation, + m.optimizeReferences, + } + else + return { + m.subSystem, + m.fullProgramDatabaseFile, + m.generateDebugInformation, + m.optimizeReferences, + m.additionalDependencies, + m.additionalLibraryDirectories, + m.importLibrary, + m.entryPointSymbol, + m.generateMapFile, + m.moduleDefinitionFile, + m.treatLinkerWarningAsErrors, + m.ignoreDefaultLibraries, + m.largeAddressAware, + m.targetMachine, + m.additionalLinkOptions, + m.programDatabaseFile, + } + end + end + + function m.link(cfg, explicit) + local contents = p.capture(function () + p.push() + p.callArray(m.elements.link, cfg, explicit) + p.pop() + end) + if #contents > 0 then + p.push('') + p.outln(contents) + p.pop('') + end + end + + + + m.elements.lib = function(cfg, explicit) + if cfg.kind == p.STATICLIB then + return { + m.additionalDependencies, + m.additionalLibraryDirectories, + m.treatLinkerWarningAsErrors, + m.targetMachine, + m.additionalLinkOptions, + } + else + return {} + end + end + + function m.lib(cfg, explicit) + local contents = p.capture(function () + p.push() + p.callArray(m.elements.lib, cfg, explicit) + p.pop() + end) + if #contents > 0 then + p.push('') + p.outln(contents) + p.pop('') + end + end + + + +-- +-- Write the manifest section. +-- + + function m.manifest(cfg) + if cfg.kind ~= p.STATICLIB then + -- get the manifests files + local manifests = {} + for _, fname in ipairs(cfg.files) do + if path.getextension(fname) == ".manifest" then + table.insert(manifests, project.getrelative(cfg.project, fname)) + end + end + + if #manifests > 0 then + p.push('') + m.element("AdditionalManifestFiles", nil, "%s %%(AdditionalManifestFiles)", table.concat(manifests, " ")) + p.pop('') + end + end + end + + + +--- +-- Write out the pre- and post-build event settings. +--- + + function m.buildEvents(cfg) + local write = function (event) + local name = event .. "Event" + local field = event:lower() + local steps = cfg[field .. "commands"] + local msg = cfg[field .. "message"] + + if #steps > 0 then + steps = os.translateCommands(steps, p.WINDOWS) + p.push('<%s>', name) + p.x('%s', table.implode(steps, "", "", "\r\n")) + if msg then + p.x('%s', msg) + end + p.pop('', name) + end + end + + write("PreBuild") + write("PreLink") + write("PostBuild") + end + + + +--- +-- Write out project-level custom rule variables. +--- + + function m.ruleVars(cfg) + for i = 1, #cfg.rules do + local rule = p.global.getRule(cfg.rules[i]) + + local contents = p.capture(function () + p.push() + for prop in p.rule.eachProperty(rule) do + local fld = p.rule.getPropertyField(rule, prop) + local value = cfg[fld.name] + if value ~= nil then + if fld.kind == "list:path" then + value = table.concat(vstudio.path(cfg, value), ';') + elseif fld.kind == "path" then + value = vstudio.path(cfg, value) + else + value = p.rule.getPropertyString(rule, prop, value) + end + + if value ~= nil and #value > 0 then + m.element(prop.name, nil, '%s', value) + end + end + end + p.pop() + end) + + if #contents > 0 then + p.push('<%s>', rule.name) + p.outln(contents) + p.pop('', rule.name) + end + end + end + + +-- +-- Reference any managed assemblies listed in the links() +-- + + function m.assemblyReferences(prj) + -- Visual Studio doesn't support per-config references; use + -- whatever is contained in the first configuration + local cfg = project.getfirstconfig(prj) + + local refs = config.getlinks(cfg, "system", "fullpath", "managed") + if #refs > 0 then + p.push('') + for i = 1, #refs do + local value = refs[i] + + -- If the link contains a '/' then it is a relative path to + -- a local assembly. Otherwise treat it as a system assembly. + if value:find('/', 1, true) then + p.push('', path.getbasename(value)) + p.x('%s', path.translate(value)) + p.pop('') + else + p.x('', path.getbasename(value)) + end + end + p.pop('') + end + end + + + function m.generatedFile(cfg, file) + if file.generated then + local path = path.translate(file.dependsOn.relpath) + m.element("AutoGen", nil, 'true') + m.element("DependentUpon", nil, path) + end + end + + +--- +-- Write out the list of source code files, and any associated configuration. +--- + + function m.files(prj) + local groups = m.categorizeSources(prj) + for _, group in ipairs(groups) do + group.category.emitFiles(prj, group) + end + end + + + m.categories = {} + +--- +-- ClInclude group +--- + m.categories.ClInclude = { + name = "ClInclude", + extensions = { ".h", ".hh", ".hpp", ".hxx", ".inl" }, + priority = 1, + + emitFiles = function(prj, group) + m.emitFiles(prj, group, "ClInclude", {m.generatedFile}) + end, + + emitFilter = function(prj, group) + m.filterGroup(prj, group, "ClInclude") + end + } + + +--- +-- ClCompile group +--- + m.categories.ClCompile = { + name = "ClCompile", + extensions = { ".cc", ".cpp", ".cxx", ".c", ".s", ".m", ".mm" }, + priority = 2, + + emitFiles = function(prj, group) + local fileCfgFunc = function(fcfg, condition) + if fcfg then + return { + m.excludedFromBuild, + m.objectFileName, + m.clCompilePreprocessorDefinitions, + m.clCompileUndefinePreprocessorDefinitions, + m.optimization, + m.forceIncludes, + m.precompiledHeader, + m.enableEnhancedInstructionSet, + m.additionalCompileOptions, + m.disableSpecificWarnings, + m.treatSpecificWarningsAsErrors, + m.basicRuntimeChecks, + m.exceptionHandling, + m.compileAsManaged, + } + else + return { + m.excludedFromBuild + } + end + end + + m.emitFiles(prj, group, "ClCompile", {m.generatedFile}, fileCfgFunc) + end, + + emitFilter = function(prj, group) + m.filterGroup(prj, group, "ClCompile") + end + } + + +--- +-- None group +--- + m.categories.None = { + name = "None", + priority = 3, + + emitFiles = function(prj, group) + m.emitFiles(prj, group, "None", {m.generatedFile}) + end, + + emitFilter = function(prj, group) + m.filterGroup(prj, group, "None") + end + } + + +--- +-- ResourceCompile group +--- + m.categories.ResourceCompile = { + name = "ResourceCompile", + extensions = ".rc", + priority = 4, + + emitFiles = function(prj, group) + local fileCfgFunc = { + m.excludedFromBuild + } + + m.emitFiles(prj, group, "ResourceCompile", nil, fileCfgFunc, function(cfg) + return cfg.system == p.WINDOWS + end) + end, + + emitFilter = function(prj, group) + m.filterGroup(prj, group, "ResourceCompile") + end + } + + +--- +-- CustomBuild group +--- + m.categories.CustomBuild = { + name = "CustomBuild", + priority = 5, + + emitFiles = function(prj, group) + local fileFunc = { + m.fileType + } + + local fileCfgFunc = { + m.excludedFromBuild, + m.buildCommands, + m.buildOutputs, + m.linkObjects, + m.buildMessage, + m.buildAdditionalInputs + } + + m.emitFiles(prj, group, "CustomBuild", fileFunc, fileCfgFunc, function (cfg, fcfg) + return fileconfig.hasCustomBuildRule(fcfg) + end) + end, + + emitFilter = function(prj, group) + m.filterGroup(prj, group, "CustomBuild") + end + } + + +--- +-- Midl group +--- + m.categories.Midl = { + name = "Midl", + extensions = ".idl", + priority = 6, + + emitFiles = function(prj, group) + local fileCfgFunc = { + m.excludedFromBuild + } + + m.emitFiles(prj, group, "Midl", nil, fileCfgFunc, function(cfg) + return cfg.system == p.WINDOWS + end) + end, + + emitFilter = function(prj, group) + m.filterGroup(prj, group, "Midl") + end + } + +--- +-- Masm group +--- + m.categories.Masm = { + name = "Masm", + extensions = ".asm", + priority = 7, + + emitFiles = function(prj, group) + local fileCfgFunc = { + m.excludedFromBuild + } + + m.emitFiles(prj, group, "Masm", nil, fileCfgFunc, function(cfg) + return cfg.system == p.WINDOWS + end) + end, + + emitFilter = function(prj, group) + m.filterGroup(prj, group, "Masm") + end, + + emitExtensionSettings = function(prj, group) + p.w('') + end, + + emitExtensionTargets = function(prj, group) + p.w('') + end + } + + +--- +-- Categorize files into groups. +--- + function m.categorizeSources(prj) + -- if we already did this, return the cached result. + if prj._vc2010_sources then + return prj._vc2010_sources + end + + -- build the new group table. + local result = {} + local groups = {} + prj._vc2010_sources = result + + local tr = project.getsourcetree(prj) + tree.traverse(tr, { + onleaf = function(node) + local cat = m.categorizeFile(prj, node) + groups[cat.name] = groups[cat.name] or { + category = cat, + files = {} + } + table.insert(groups[cat.name].files, node) + end + }) + + -- sort by relative-to path; otherwise VS will reorder the files + for name, group in pairs(groups) do + table.sort(group.files, function (a, b) + return a.relpath < b.relpath + end) + table.insert(result, group) + end + + -- sort by category priority then name; so we get stable results. + table.sort(result, function (a, b) + if (a.category.priority == b.category.priority) then + return a.category.name < b.category.name + end + return a.category.priority < b.category.priority + end) + + return result + end + + + function m.categorizeFile(prj, file) + -- If any configuration for this file uses a custom build step, + -- that's the category to use + for cfg in project.eachconfig(prj) do + local fcfg = fileconfig.getconfig(file, cfg) + if fileconfig.hasCustomBuildRule(fcfg) then + return m.categories.CustomBuild + end + end + + -- If there is a custom rule associated with it, use that + local rule = p.global.getRuleForFile(file.name, prj.rules) + if rule then + return { + name = rule.name, + priority = 100, + rule = rule, + emitFiles = function(prj, group) + m.emitRuleFiles(prj, group) + end, + emitFilter = function(prj, group) + m.filterGroup(prj, group, group.category.name) + end + } + end + + -- Otherwise use the file extension to deduce a category + for _, cat in pairs(m.categories) do + if cat.extensions and path.hasextension(file.name, cat.extensions) then + return cat + end + end + + return m.categories.None + end + + + function m.emitFiles(prj, group, tag, fileFunc, fileCfgFunc, checkFunc) + local files = group.files + if files and #files > 0 then + p.push('') + for _, file in ipairs(files) do + + local contents = p.capture(function () + p.push() + p.callArray(fileFunc, cfg, file) + for cfg in project.eachconfig(prj) do + local fcfg = fileconfig.getconfig(file, cfg) + if not checkFunc or checkFunc(cfg, fcfg) then + p.callArray(fileCfgFunc, fcfg, m.condition(cfg)) + end + end + p.pop() + end) + + local rel = path.translate(file.relpath) + if #contents > 0 then + p.push('<%s Include="%s">', tag, rel) + p.outln(contents) + p.pop('', tag) + else + p.x('<%s Include="%s" />', tag, rel) + end + + end + p.pop('') + end + end + + function m.emitRuleFiles(prj, group) + local files = group.files + local rule = group.category.rule + + if files and #files > 0 then + p.push('') + + for _, file in ipairs(files) do + local contents = p.capture(function() + p.push() + for prop in p.rule.eachProperty(rule) do + local fld = p.rule.getPropertyField(rule, prop) + + for cfg in project.eachconfig(prj) do + local fcfg = fileconfig.getconfig(file, cfg) + if fcfg and fcfg[fld.name] then + local value = p.rule.getPropertyString(rule, prop, fcfg[fld.name]) + if value and #value > 0 then + m.element(prop.name, m.condition(cfg), '%s', value) + end + end + end + + end + p.pop() + end) + + if #contents > 0 then + p.push('<%s Include=\"%s\">', rule.name, path.translate(file.relpath)) + p.outln(contents) + p.pop('', rule.name) + else + p.x('<%s Include=\"%s\" />', rule.name, path.translate(file.relpath)) + end + end + + p.pop('') + end + end + + + function m.isClrMixed(prj) + -- check to see if any files are marked with clr + local isMixed = false + if not prj.clr or prj.clr == p.OFF then + if prj._isClrMixed ~= nil then + isMixed = prj._isClrMixed + else + table.foreachi(prj._.files, function(file) + for cfg in p.project.eachconfig(prj) do + local fcfg = p.fileconfig.getconfig(file, cfg) + if fcfg and fcfg.clr and fcfg.clr ~= p.OFF then + isMixed = true + end + end + end) + prj._isClrMixed = isMixed -- cache the results + end + end + return isMixed + end + + +-- +-- Generate the list of project dependencies. +-- + + m.elements.projectReferences = function(prj, ref) + if prj.clr ~= p.OFF or (m.isClrMixed(prj) and ref and ref.kind ~=p.STATICLIB) then + return { + m.referenceProject, + m.referencePrivate, + m.referenceOutputAssembly, + m.referenceCopyLocalSatelliteAssemblies, + m.referenceLinkLibraryDependencies, + m.referenceUseLibraryDependences, + } + else + return { + m.referenceProject, + } + end + end + + function m.projectReferences(prj) + local refs = project.getdependencies(prj, 'linkOnly') + if #refs > 0 then + p.push('') + for _, ref in ipairs(refs) do + local relpath = vstudio.path(prj, vstudio.projectfile(ref)) + p.push('', relpath) + p.callArray(m.elements.projectReferences, prj, ref) + p.pop('') + end + p.pop('') + end + end + + + +--------------------------------------------------------------------------- +-- +-- Handlers for individual project elements +-- +--------------------------------------------------------------------------- + + function m.additionalDependencies(cfg, explicit) + local links + + -- check to see if this project uses an external toolset. If so, let the + -- toolset define the format of the links + local toolset = config.toolset(cfg) + if toolset then + links = toolset.getlinks(cfg, not explicit) + else + links = vstudio.getLinks(cfg, explicit) + end + + if #links > 0 then + links = path.translate(table.concat(links, ";")) + m.element("AdditionalDependencies", nil, "%s;%%(AdditionalDependencies)", links) + end + end + + + function m.additionalIncludeDirectories(cfg, includedirs) + if #includedirs > 0 then + local dirs = vstudio.path(cfg, includedirs) + if #dirs > 0 then + m.element("AdditionalIncludeDirectories", nil, "%s;%%(AdditionalIncludeDirectories)", table.concat(dirs, ";")) + end + end + end + + + function m.additionalLibraryDirectories(cfg) + if #cfg.libdirs > 0 then + local dirs = table.concat(vstudio.path(cfg, cfg.libdirs), ";") + m.element("AdditionalLibraryDirectories", nil, "%s;%%(AdditionalLibraryDirectories)", dirs) + end + end + + + function m.additionalUsingDirectories(cfg) + if #cfg.usingdirs > 0 then + local dirs = vstudio.path(cfg, cfg.usingdirs) + if #dirs > 0 then + m.element("AdditionalUsingDirectories", nil, "%s;%%(AdditionalUsingDirectories)", table.concat(dirs, ";")) + end + end + end + + + function m.largeAddressAware(cfg) + if (cfg.largeaddressaware == true) then + m.element("LargeAddressAware", nil, 'true') + end + end + + + function m.additionalCompileOptions(cfg, condition) + if #cfg.buildoptions > 0 then + local opts = table.concat(cfg.buildoptions, " ") + m.element("AdditionalOptions", condition, '%s %%(AdditionalOptions)', opts) + end + end + + + function m.additionalLinkOptions(cfg) + if #cfg.linkoptions > 0 then + local opts = table.concat(cfg.linkoptions, " ") + m.element("AdditionalOptions", nil, "%s %%(AdditionalOptions)", opts) + end + end + + + function m.compileAsManaged(fcfg, condition) + if fcfg.clr and fcfg ~= p.OFF then + m.element("CompileAsManaged", condition, "true") + end + end + + + function m.basicRuntimeChecks(cfg, condition) + local prjcfg, filecfg = p.config.normalize(cfg) + local runtime = config.getruntime(prjcfg) + if filecfg then + if filecfg.flags.NoRuntimeChecks or (config.isOptimizedBuild(filecfg) and runtime:endswith("Debug")) then + m.element("BasicRuntimeChecks", condition, "Default") + end + else + if prjcfg.flags.NoRuntimeChecks or (config.isOptimizedBuild(prjcfg) and runtime:endswith("Debug")) then + m.element("BasicRuntimeChecks", nil, "Default") + end + end + end + + + function m.buildAdditionalInputs(fcfg, condition) + if fcfg.buildinputs and #fcfg.buildinputs > 0 then + local inputs = project.getrelative(fcfg.project, fcfg.buildinputs) + m.element("AdditionalInputs", condition, '%s', table.concat(inputs, ";")) + end + end + + + function m.buildCommands(fcfg, condition) + local commands = os.translateCommands(fcfg.buildcommands, p.WINDOWS) + commands = table.concat(commands,'\r\n') + m.element("Command", condition, '%s', commands) + end + + + function m.buildLog(cfg) + if cfg.buildlog and #cfg.buildlog > 0 then + p.push('') + m.element("Path", nil, "%s", vstudio.path(cfg, cfg.buildlog)) + p.pop('') + end + end + + + function m.buildMessage(fcfg, condition) + if fcfg.buildmessage then + m.element("Message", condition, '%s', fcfg.buildmessage) + end + end + + + function m.buildOutputs(fcfg, condition) + local outputs = project.getrelative(fcfg.project, fcfg.buildoutputs) + m.element("Outputs", condition, '%s', table.concat(outputs, ";")) + end + + + function m.linkObjects(fcfg, condition) + if fcfg.linkbuildoutputs ~= nil then + m.element("LinkObjects", condition, tostring(fcfg.linkbuildoutputs)) + end + end + + + function m.characterSet(cfg) + if not vstudio.isMakefile(cfg) then + m.element("CharacterSet", nil, iif(cfg.characterset == p.MBCS, "MultiByte", "Unicode")) + end + end + + + function m.wholeProgramOptimization(cfg) + if cfg.flags.LinkTimeOptimization then + m.element("WholeProgramOptimization", nil, "true") + end + end + + function m.clCompileAdditionalIncludeDirectories(cfg) + m.additionalIncludeDirectories(cfg, cfg.includedirs) + end + + function m.clCompileAdditionalUsingDirectories(cfg) + m.additionalUsingDirectories(cfg, cfg.usingdirs) + end + + + function m.clCompilePreprocessorDefinitions(cfg, condition) + local defines = cfg.defines + if cfg.exceptionhandling == p.OFF and _ACTION >= "vs2013" then + defines = table.join(defines, "_HAS_EXCEPTIONS=0") + end + m.preprocessorDefinitions(cfg, defines, false, condition) + end + + + function m.clCompileUndefinePreprocessorDefinitions(cfg, condition) + m.undefinePreprocessorDefinitions(cfg, cfg.undefines, false, condition) + end + + + function m.clrSupport(cfg) + local value + if cfg.clr == "On" or cfg.clr == "Unsafe" then + value = "true" + elseif cfg.clr ~= p.OFF then + value = cfg.clr + end + if value then + m.element("CLRSupport", nil, value) + end + end + + + function m.compileAs(cfg) + if p.languages.isc(cfg.language) then + m.element("CompileAs", nil, "CompileAsC") + end + end + + + function m.configurationType(cfg) + local types = { + SharedLib = "DynamicLibrary", + StaticLib = "StaticLibrary", + ConsoleApp = "Application", + WindowedApp = "Application", + Makefile = "Makefile", + None = "Makefile", + Utility = "Utility", + } + m.element("ConfigurationType", nil, types[cfg.kind]) + end + + + function m.culture(cfg) + local value = vstudio.cultureForLocale(cfg.locale) + if value then + m.element("Culture", nil, "0x%04x", tostring(value)) + end + end + + + function m.debugInformationFormat(cfg) + local value + local tool, toolVersion = p.config.toolset(cfg) + if (cfg.symbols == p.ON) or (cfg.symbols == "FastLink") then + if cfg.debugformat == "c7" then + value = "OldStyle" + elseif (cfg.architecture == "x86_64" and _ACTION < "vs2015") or + cfg.clr ~= p.OFF or + config.isOptimizedBuild(cfg) or + cfg.editandcontinue == p.OFF or + (toolVersion and toolVersion:startswith("LLVM-vs")) + then + value = "ProgramDatabase" + else + value = "EditAndContinue" + end + + m.element("DebugInformationFormat", nil, value) + elseif cfg.symbols == p.OFF then + -- leave field blank for vs2013 and older to workaround bug if _ACTION < "vs2015" then value = "" else @@ -1270,982 +1270,982 @@ end m.element("DebugInformationFormat", nil, value) - end - end - - - function m.deploy(cfg) - if cfg.system == p.XBOX360 then - p.push('') - m.element("DeploymentType", nil, "CopyToHardDrive") - m.element("DvdEmulationType", nil, "ZeroSeekTimes") - m.element("DeploymentFiles", nil, "$(RemoteRoot)=$(ImagePath);") - p.pop('') - end - end - - - function m.enableEnhancedInstructionSet(cfg, condition) - local v - local x = cfg.vectorextensions - if x == "AVX" and _ACTION > "vs2010" then - v = "AdvancedVectorExtensions" - elseif x == "AVX2" and _ACTION > "vs2012" then - v = "AdvancedVectorExtensions2" - elseif cfg.architecture ~= "x86_64" then - if x == "SSE2" or x == "SSE3" or x == "SSSE3" or x == "SSE4.1" then - v = "StreamingSIMDExtensions2" - elseif x == "SSE" then - v = "StreamingSIMDExtensions" - elseif x == "IA32" and _ACTION > "vs2010" then - v = "NoExtensions" - end - end - if v then - m.element('EnableEnhancedInstructionSet', condition, v) - end - end - - - function m.entryPointSymbol(cfg) - if cfg.entrypoint then - m.element("EntryPointSymbol", nil, cfg.entrypoint) - else - if (cfg.kind == premake.CONSOLEAPP or cfg.kind == premake.WINDOWEDAPP) and - not cfg.flags.WinMain and - cfg.clr == p.OFF and - cfg.system ~= p.XBOX360 - then - m.element("EntryPointSymbol", nil, "mainCRTStartup") - end - end - end - - - function m.exceptionHandling(cfg, condition) - if cfg.exceptionhandling == p.OFF then - m.element("ExceptionHandling", condition, "false") - elseif cfg.exceptionhandling == "SEH" then - m.element("ExceptionHandling", condition, "Async") - end - end - - - function m.excludedFromBuild(filecfg, condition) - if not filecfg or filecfg.flags.ExcludeFromBuild then - m.element("ExcludedFromBuild", condition, "true") - end - end - - - function m.extensionsToDeleteOnClean(cfg) - if #cfg.cleanextensions > 0 then - local value = table.implode(cfg.cleanextensions, "*", ";", "") - m.element("ExtensionsToDeleteOnClean", nil, value .. "$(ExtensionsToDeleteOnClean)") - end - end - - - function m.fileType(cfg, file) - m.element("FileType", nil, "Document") - end - - - function m.floatingPointModel(cfg) - if cfg.floatingpoint and cfg.floatingpoint ~= "Default" then - m.element("FloatingPointModel", nil, cfg.floatingpoint) - end - end - - - function m.floatingPointExceptions(cfg) - if cfg.floatingpointexceptions ~= nil then - if cfg.floatingpointexceptions then - m.element("FloatingPointExceptions", nil, "true") - else - m.element("FloatingPointExceptions", nil, "false") - end - end - end - - - function m.inlineFunctionExpansion(cfg) - if cfg.inlining then - local types = { - Default = "Default", - Disabled = "Disabled", - Explicit = "OnlyExplicitInline", - Auto = "AnySuitable", - } - m.element("InlineFunctionExpansion", nil, types[cfg.inlining]) - end - end - - - function m.forceIncludes(cfg, condition) - if #cfg.forceincludes > 0 then - local includes = vstudio.path(cfg, cfg.forceincludes) - if #includes > 0 then - m.element("ForcedIncludeFiles", condition, table.concat(includes, ';')) - end - end - if #cfg.forceusings > 0 then - local usings = vstudio.path(cfg, cfg.forceusings) - if #usings > 0 then - m.element("ForcedUsingFiles", condition, table.concat(usings, ';')) - end - end - end - - - function m.fullProgramDatabaseFile(cfg) - if _ACTION >= "vs2015" and cfg.symbols == "FastLink" then - m.element("FullProgramDatabaseFile", nil, "true") - end - end - - - function m.functionLevelLinking(cfg) - if cfg.functionlevellinking ~= nil then - if cfg.functionlevellinking then - m.element("FunctionLevelLinking", nil, "true") - else - m.element("FunctionLevelLinking", nil, "false") - end - elseif config.isOptimizedBuild(cfg) then - m.element("FunctionLevelLinking", nil, "true") - end - end - - - function m.generateDebugInformation(cfg) - local lookup = {} - if _ACTION >= "vs2017" then - lookup[p.ON] = "true" - lookup[p.OFF] = "false" - lookup["FastLink"] = "DebugFastLink" - lookup["Full"] = "DebugFull" - elseif _ACTION == "vs2015" then - lookup[p.ON] = "true" - lookup[p.OFF] = "false" - lookup["FastLink"] = "DebugFastLink" - lookup["Full"] = "true" - else - lookup[p.ON] = "true" - lookup[p.OFF] = "false" - lookup["FastLink"] = "true" - lookup["Full"] = "true" - end - - local value = lookup[cfg.symbols] - if value then - m.element("GenerateDebugInformation", nil, value) - end - end - - - function m.generateManifest(cfg) - if cfg.flags.NoManifest then - m.element("GenerateManifest", nil, "false") - end - end - - - function m.generateMapFile(cfg) - if cfg.flags.Maps then - m.element("GenerateMapFile", nil, "true") - end - end - - - function m.ignoreDefaultLibraries(cfg) - if #cfg.ignoredefaultlibraries > 0 then - local ignored = cfg.ignoredefaultlibraries - for i = 1, #ignored do - -- Add extension if required - if not p.tools.msc.getLibraryExtensions()[ignored[i]:match("[^.]+$")] then - ignored[i] = path.appendextension(ignored[i], ".lib") - end - end - - m.element("IgnoreSpecificDefaultLibraries", condition, table.concat(ignored, ';')) - end - end - - - function m.ignoreWarnDuplicateFilename(prj) - -- VS 2013 warns on duplicate file names, even those files which are - -- contained in different, mututally exclusive configurations. See: - -- http://connect.microsoft.com/VisualStudio/feedback/details/797460/incorrect-warning-msb8027-reported-for-files-excluded-from-build - -- Premake already adds unique object names to conflicting file names, so - -- just go ahead and disable that warning. - if _ACTION > "vs2012" then - m.element("IgnoreWarnCompileDuplicatedFilename", nil, "true") - end - end - - - function m.ignoreImportLibrary(cfg) - if cfg.kind == p.SHAREDLIB and cfg.flags.NoImportLib then - m.element("IgnoreImportLibrary", nil, "true") - end - end - - - function m.imageXex(cfg) - if cfg.system == p.XBOX360 then - p.push('') - if cfg.configfile then - m.element("ConfigurationFile", nil, "%s", cfg.configfile) - else - p.w('') - p.w('') - end - p.w('') - p.w('') - p.pop('') - end - end - - - function m.imageXexOutput(cfg) - if cfg.system == p.XBOX360 then - m.element("ImageXexOutput", nil, "%s", "$(OutDir)$(TargetName).xex") - end - end - - - function m.importLanguageTargets(prj) - p.w('') - end - - m.elements.importExtensionTargets = function(prj) - return { - m.importGroupTargets, - m.importRuleTargets, - m.importNuGetTargets, - m.importBuildCustomizationsTargets - } - end - - function m.importExtensionTargets(prj) - p.push('') - p.callArray(m.elements.importExtensionTargets, prj) - p.pop('') - end - - function m.importGroupTargets(prj) - local groups = m.categorizeSources(prj) - for _, group in ipairs(groups) do - if group.category.emitExtensionTargets then - group.category.emitExtensionTargets(prj, group) - end - end - end - - function m.importRuleTargets(prj) - for i = 1, #prj.rules do - local rule = p.global.getRule(prj.rules[i]) - local loc = vstudio.path(prj, p.filename(rule, ".targets")) - p.x('', loc) - end - end - - local function nuGetTargetsFile(prj, package) - return p.vstudio.path(prj, p.filename(prj.solution, string.format("packages\\%s\\build\\native\\%s.targets", vstudio.nuget2010.packageName(package), vstudio.nuget2010.packageId(package)))) - end - - function m.importNuGetTargets(prj) - for i = 1, #prj.nuget do - local targetsFile = nuGetTargetsFile(prj, prj.nuget[i]) - p.x('', targetsFile, targetsFile) - end - end - - function m.importBuildCustomizationsTargets(prj) - for i, build in ipairs(prj.buildcustomizations) do - p.w('', path.translate(build)) - end - end - - - - function m.ensureNuGetPackageBuildImports(prj) - if #prj.nuget > 0 then - p.push('') - p.push('') - p.x('This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.') - p.pop('') - - for i = 1, #prj.nuget do - local targetsFile = nuGetTargetsFile(prj, prj.nuget[i]) - p.x('', targetsFile, targetsFile) - end - p.pop('') - end - end - - - - function m.importDefaultProps(prj) - p.w('') - end - - - - function m.importLanguageSettings(prj) - p.w('') - end - - m.elements.importExtensionSettings = function(prj) - return { - m.importGroupSettings, - m.importRuleSettings, - m.importBuildCustomizationsProps - } - end - - function m.importExtensionSettings(prj) - p.push('') - p.callArray(m.elements.importExtensionSettings, prj) - p.pop('') - end - - - function m.importGroupSettings(prj) - local groups = m.categorizeSources(prj) - for _, group in ipairs(groups) do - if group.category.emitExtensionSettings then - group.category.emitExtensionSettings(prj, group) - end - end - end - - - function m.importRuleSettings(prj) - for i = 1, #prj.rules do - local rule = p.global.getRule(prj.rules[i]) - local loc = vstudio.path(prj, p.filename(rule, ".props")) - p.x('', loc) - end - end - - - function m.importBuildCustomizationsProps(prj) - for i, build in ipairs(prj.buildcustomizations) do - p.w('', path.translate(build)) - end - end - - - - function m.importLibrary(cfg) - if cfg.kind == p.SHAREDLIB then - m.element("ImportLibrary", nil, "%s", path.translate(cfg.linktarget.relpath)) - end - end - - - function m.includePath(cfg) - local dirs = vstudio.path(cfg, cfg.sysincludedirs) - if #dirs > 0 then - m.element("IncludePath", nil, "%s;$(IncludePath)", table.concat(dirs, ";")) - end - end - - - function m.intDir(cfg) - local objdir = vstudio.path(cfg, cfg.objdir) - m.element("IntDir", nil, "%s\\", objdir) - end - - - function m.intrinsicFunctions(cfg) - if cfg.intrinsics ~= nil then - if cfg.intrinsics then - m.element("IntrinsicFunctions", nil, "true") - else - m.element("IntrinsicFunctions", nil, "false") - end - elseif config.isOptimizedBuild(cfg) then - m.element("IntrinsicFunctions", nil, "true") - end - end - - - function m.keyword(prj) - -- try to determine what kind of targets we're building here - local isWin, isManaged, isMakefile - for cfg in project.eachconfig(prj) do - if cfg.system == p.WINDOWS then - isWin = true - end - if cfg.clr ~= p.OFF then - isManaged = true - end - if vstudio.isMakefile(cfg) then - isMakefile = true - end - end - - if isWin then - if isMakefile then - m.element("Keyword", nil, "MakeFileProj") - else - if isManaged or m.isClrMixed(prj) then - m.targetFramework(prj) - end - if isManaged then - m.element("Keyword", nil, "ManagedCProj") - else - m.element("Keyword", nil, "Win32Proj") - end - m.element("RootNamespace", nil, "%s", prj.name) - end - end - end - - - function m.libraryPath(cfg) - local dirs = vstudio.path(cfg, cfg.syslibdirs) - if #dirs > 0 then - m.element("LibraryPath", nil, "%s;$(LibraryPath)", table.concat(dirs, ";")) - end - end - - - - function m.linkIncremental(cfg) - if cfg.kind ~= p.STATICLIB then - m.element("LinkIncremental", nil, "%s", tostring(config.canLinkIncremental(cfg))) - end - end - - - function m.linkLibraryDependencies(cfg, explicit) - -- Left to its own devices, VS will happily link against a project dependency - -- that has been excluded from the build. As a workaround, disable dependency - -- linking and list all siblings explicitly - if explicit then - p.push('') - m.element("LinkLibraryDependencies", nil, "false") - p.pop('') - end - end - - - function m.minimalRebuild(cfg) - if config.isOptimizedBuild(cfg) or - cfg.flags.NoMinimalRebuild or - cfg.flags.MultiProcessorCompile or - cfg.debugformat == p.C7 - then - m.element("MinimalRebuild", nil, "false") - end - end - - - function m.moduleDefinitionFile(cfg) - local df = config.findfile(cfg, ".def") - if df then - m.element("ModuleDefinitionFile", nil, "%s", df) - end - end - - - function m.multiProcessorCompilation(cfg) - if cfg.flags.MultiProcessorCompile then - m.element("MultiProcessorCompilation", nil, "true") - end - end - - - function m.nmakeBuildCommands(cfg) - m.nmakeCommandLine(cfg, cfg.buildcommands, "Build") - end - - - function m.nmakeCleanCommands(cfg) - m.nmakeCommandLine(cfg, cfg.cleancommands, "Clean") - end - - - function m.nmakeCommandLine(cfg, commands, phase) - if #commands > 0 then - commands = os.translateCommands(commands, p.WINDOWS) - commands = table.concat(p.esc(commands), p.eol()) - p.w('%s', phase, commands, phase) - end - end - - - function m.nmakeIncludeDirs(cfg) - if cfg.kind ~= p.NONE and #cfg.includedirs > 0 then - local dirs = vstudio.path(cfg, cfg.includedirs) - if #dirs > 0 then - m.element("NMakeIncludeSearchPath", nil, "%s", table.concat(dirs, ";")) - end - end - end - - - function m.nmakeOutDirs(cfg) - if vstudio.isMakefile(cfg) then - m.outDir(cfg) - m.intDir(cfg) - end - end - - - function m.nmakeOutput(cfg) - m.element("NMakeOutput", nil, "$(OutDir)%s", cfg.buildtarget.name) - end - - - function m.nmakePreprocessorDefinitions(cfg) - if cfg.kind ~= p.NONE and #cfg.defines > 0 then - local defines = table.concat(cfg.defines, ";") - defines = p.esc(defines) .. ";$(NMakePreprocessorDefinitions)" - m.element('NMakePreprocessorDefinitions', nil, defines) - end - end - - - function m.nmakeRebuildCommands(cfg) - m.nmakeCommandLine(cfg, cfg.rebuildcommands, "ReBuild") - end - - - function m.objectFileName(fcfg) - if fcfg.objname ~= fcfg.basename then - m.element("ObjectFileName", m.condition(fcfg.config), "$(IntDir)\\%s.obj", fcfg.objname) - end - end - - - - function m.omitDefaultLib(cfg) - if cfg.flags.OmitDefaultLibrary then - m.element("OmitDefaultLibName", nil, "true") - end - end - - - - function m.omitFramePointers(cfg) - if cfg.flags.NoFramePointer then - m.element("OmitFramePointers", nil, "true") - end - end - - - function m.optimizeReferences(cfg) - if config.isOptimizedBuild(cfg) then - m.element("EnableCOMDATFolding", nil, "true") - m.element("OptimizeReferences", nil, "true") - end - end - - - function m.optimization(cfg, condition) - local map = { Off="Disabled", On="Full", Debug="Disabled", Full="Full", Size="MinSpace", Speed="MaxSpeed" } - local value = map[cfg.optimize] - if value or not condition then - m.element('Optimization', condition, value or "Disabled") - end - end - - - function m.outDir(cfg) - local outdir = vstudio.path(cfg, cfg.buildtarget.directory) - m.element("OutDir", nil, "%s\\", outdir) - end - - - function m.outputFile(cfg) - if cfg.system == p.XBOX360 then - m.element("OutputFile", nil, "$(OutDir)%s", cfg.buildtarget.name) - end - end - - - function m.executablePath(cfg) - local dirs = vstudio.path(cfg, cfg.bindirs) - if #dirs > 0 then - m.element("ExecutablePath", nil, "%s;$(ExecutablePath)", table.concat(dirs, ";")) - end - end - - - function m.platformToolset(cfg) - local tool, version = p.config.toolset(cfg) - if not version then - local action = p.action.current() - version = action.vstudio.platformToolset - end - if version then - if cfg.kind == p.NONE or cfg.kind == p.MAKEFILE then - if p.config.hasFile(cfg, path.iscppfile) then - m.element("PlatformToolset", nil, version) - end - else - m.element("PlatformToolset", nil, version) - end - end - end - - - function m.precompiledHeader(cfg, condition) - prjcfg, filecfg = p.config.normalize(cfg) - if filecfg then - if prjcfg.pchsource == filecfg.abspath and not prjcfg.flags.NoPCH then - m.element('PrecompiledHeader', condition, 'Create') - elseif filecfg.flags.NoPCH then - m.element('PrecompiledHeader', condition, 'NotUsing') - end - else - if not prjcfg.flags.NoPCH and prjcfg.pchheader then - m.element("PrecompiledHeader", nil, "Use") - m.element("PrecompiledHeaderFile", nil, "%s", prjcfg.pchheader) - else - m.element("PrecompiledHeader", nil, "NotUsing") - end - end - end - - - function m.preprocessorDefinitions(cfg, defines, escapeQuotes, condition) - if #defines > 0 then - defines = table.concat(defines, ";") - if escapeQuotes then - defines = defines:gsub('"', '\\"') - end - defines = p.esc(defines) .. ";%%(PreprocessorDefinitions)" - m.element('PreprocessorDefinitions', condition, defines) - end - end - - - function m.undefinePreprocessorDefinitions(cfg, undefines, escapeQuotes, condition) - if #undefines > 0 then - undefines = table.concat(undefines, ";") - if escapeQuotes then - undefines = undefines:gsub('"', '\\"') - end - undefines = p.esc(undefines) .. ";%%(UndefinePreprocessorDefinitions)" - m.element('UndefinePreprocessorDefinitions', condition, undefines) - end - end - - - function m.programDatabaseFile(cfg) - if cfg.symbolspath and cfg.symbols == p.ON and cfg.debugformat ~= "c7" then - m.element("ProgramDatabaseFile", nil, p.project.getrelative(cfg.project, cfg.symbolspath)) - end - end - - - function m.projectGuid(prj) - m.element("ProjectGuid", nil, "{%s}", prj.uuid) - end - - - function m.projectName(prj) - if prj.name ~= prj.filename then - m.element("ProjectName", nil, "%s", prj.name) - end - end - - - function m.propertyGroup(cfg, label) - local cond - if cfg then - cond = string.format(' %s', m.condition(cfg)) - end - - if label then - label = string.format(' Label="%s"', label) - end - - p.push('', cond or "", label or "") - end - - - - function m.propertySheets(cfg) - p.push('', m.condition(cfg)) - p.w('') - p.pop('') - end - - - function m.propertySheetGroup(prj) - for cfg in project.eachconfig(prj) do - m.propertySheets(cfg) - end - end - - - function m.referenceCopyLocalSatelliteAssemblies(prj, ref) - m.element("CopyLocalSatelliteAssemblies", nil, "false") - end - - - function m.referenceLinkLibraryDependencies(prj, ref) - m.element("LinkLibraryDependencies", nil, "true") - end - - - function m.referenceOutputAssembly(prj, ref) - m.element("ReferenceOutputAssembly", nil, "true") - end - - - function m.referencePrivate(prj, ref) - m.element("Private", nil, "true") - end - - - function m.referenceProject(prj, ref) - m.element("Project", nil, "{%s}", ref.uuid) - end - - - function m.referenceUseLibraryDependences(prj, ref) - m.element("UseLibraryDependencyInputs", nil, "false") - end - - - function m.resourceAdditionalIncludeDirectories(cfg) - m.additionalIncludeDirectories(cfg, table.join(cfg.includedirs, cfg.resincludedirs)) - end - - - function m.resourcePreprocessorDefinitions(cfg) - local defines = table.join(cfg.defines, cfg.resdefines) - if cfg.exceptionhandling == p.OFF and _ACTION >= "vs2013" then - table.insert(defines, "_HAS_EXCEPTIONS=0") - end - m.preprocessorDefinitions(cfg, defines, true) - end - - - function m.runtimeLibrary(cfg) - local runtimes = { - StaticDebug = "MultiThreadedDebug", - StaticRelease = "MultiThreaded", - } - local runtime = runtimes[config.getruntime(cfg)] - if runtime then - m.element("RuntimeLibrary", nil, runtime) - end - end - - function m.callingConvention(cfg) - if cfg.callingconvention then - m.element("CallingConvention", nil, cfg.callingconvention) - end - end - - function m.runtimeTypeInfo(cfg) - if cfg.rtti == p.OFF and cfg.clr == p.OFF then - m.element("RuntimeTypeInfo", nil, "false") - elseif cfg.rtti == p.ON then - m.element("RuntimeTypeInfo", nil, "true") - end - end - - function m.bufferSecurityCheck(cfg) - local tool, toolVersion = p.config.toolset(cfg) - if cfg.flags.NoBufferSecurityCheck or (toolVersion and toolVersion:startswith("LLVM-vs")) then - m.element("BufferSecurityCheck", nil, "false") - end - end - - function m.stringPooling(cfg) - if cfg.stringpooling ~= nil then - if cfg.stringpooling then - m.element("StringPooling", nil, "true") - else - m.element("StringPooling", nil, "false") - end - elseif config.isOptimizedBuild(cfg) then - m.element("StringPooling", nil, "true") - end - end - - - function m.subSystem(cfg) - if cfg.system ~= p.XBOX360 then - local subsystem = iif(cfg.kind == p.CONSOLEAPP, "Console", "Windows") - m.element("SubSystem", nil, subsystem) - end - end - - - function m.targetExt(cfg) - local ext = cfg.buildtarget.extension - if ext ~= "" then - m.element("TargetExt", nil, "%s", ext) - else - p.w('') - p.w('') - end - end - - - function m.targetMachine(cfg) - -- If a static library project contains a resource file, VS will choke with - -- "LINK : warning LNK4068: /MACHINE not specified; defaulting to X86" - local targetmachine = { - x86 = "MachineX86", - x86_64 = "MachineX64", - } - if cfg.kind == p.STATICLIB and config.hasFile(cfg, path.isresourcefile) then - local value = targetmachine[cfg.architecture] - if value ~= nil then - m.element("TargetMachine", nil, '%s', value) - end - end - end - - - function m.targetName(cfg) - m.element("TargetName", nil, "%s%s", cfg.buildtarget.prefix, cfg.buildtarget.basename) - end - - - function m.targetPlatformVersion(prj) - local min = project.systemversion(prj) - if min ~= nil and _ACTION >= "vs2015" then - m.element("WindowsTargetPlatformVersion", nil, min) - end - end - - - function m.treatLinkerWarningAsErrors(cfg) - if cfg.flags.FatalLinkWarnings then - local el = iif(cfg.kind == p.STATICLIB, "Lib", "Linker") - m.element("Treat" .. el .. "WarningAsErrors", nil, "true") - end - end - - - function m.treatWChar_tAsBuiltInType(cfg) - local map = { On = "true", Off = "false" } - local value = map[cfg.nativewchar] - if value then - m.element("TreatWChar_tAsBuiltInType", nil, value) - end - end - - - function m.treatWarningAsError(cfg) - if cfg.flags.FatalCompileWarnings and cfg.warnings ~= p.OFF then - m.element("TreatWarningAsError", nil, "true") - end - end - - - function m.disableSpecificWarnings(cfg, condition) - if #cfg.disablewarnings > 0 then - local warnings = table.concat(cfg.disablewarnings, ";") - warnings = p.esc(warnings) .. ";%%(DisableSpecificWarnings)" - m.element('DisableSpecificWarnings', condition, warnings) - end - end - - - function m.treatSpecificWarningsAsErrors(cfg, condition) - if #cfg.fatalwarnings > 0 then - local fatal = table.concat(cfg.fatalwarnings, ";") - fatal = p.esc(fatal) .. ";%%(TreatSpecificWarningsAsErrors)" - m.element('TreatSpecificWarningsAsErrors', condition, fatal) - end - end - - - function m.useDebugLibraries(cfg) - local runtime = config.getruntime(cfg) - m.element("UseDebugLibraries", nil, tostring(runtime:endswith("Debug"))) - end - - - function m.useOfMfc(cfg) - if cfg.flags.MFC then - m.element("UseOfMfc", nil, iif(cfg.flags.StaticRuntime, "Static", "Dynamic")) - end - end - - function m.useOfAtl(cfg) - if cfg.atl then - m.element("UseOfATL", nil, cfg.atl) - end - end - - - - function m.userMacros(cfg) - p.w('') - end - - - - function m.warningLevel(cfg) - local map = { Off = "TurnOffAllWarnings", Extra = "Level4" } - m.element("WarningLevel", nil, "%s", map[cfg.warnings] or "Level3") - end - - - - function m.xmlDeclaration() - p.xmlUtf8() - end - - - ---------------------------------------------------------------------------- --- --- Support functions --- ---------------------------------------------------------------------------- - --- --- Format and return a Visual Studio Condition attribute. --- - - function m.condition(cfg) - return string.format('Condition="\'$(Configuration)|$(Platform)\'==\'%s\'"', p.esc(vstudio.projectConfig(cfg))) - end - - --- --- Output an individual project XML element, with an optional configuration --- condition. --- --- @param depth --- How much to indent the element. --- @param name --- The element name. --- @param condition --- An optional configuration condition, formatted with vc2010.condition(). --- @param value --- The element value, which may contain printf formatting tokens. --- @param ... --- Optional additional arguments to satisfy any tokens in the value. --- - - function m.element(name, condition, value, ...) - if select('#',...) == 0 then - value = p.esc(value) - end - - local format - if condition then - format = string.format('<%s %s>%s', name, condition, value, name) - else - format = string.format('<%s>%s', name, value, name) - end - - p.x(format, ...) - end + end + end + + + function m.deploy(cfg) + if cfg.system == p.XBOX360 then + p.push('') + m.element("DeploymentType", nil, "CopyToHardDrive") + m.element("DvdEmulationType", nil, "ZeroSeekTimes") + m.element("DeploymentFiles", nil, "$(RemoteRoot)=$(ImagePath);") + p.pop('') + end + end + + + function m.enableEnhancedInstructionSet(cfg, condition) + local v + local x = cfg.vectorextensions + if x == "AVX" and _ACTION > "vs2010" then + v = "AdvancedVectorExtensions" + elseif x == "AVX2" and _ACTION > "vs2012" then + v = "AdvancedVectorExtensions2" + elseif cfg.architecture ~= "x86_64" then + if x == "SSE2" or x == "SSE3" or x == "SSSE3" or x == "SSE4.1" then + v = "StreamingSIMDExtensions2" + elseif x == "SSE" then + v = "StreamingSIMDExtensions" + elseif x == "IA32" and _ACTION > "vs2010" then + v = "NoExtensions" + end + end + if v then + m.element('EnableEnhancedInstructionSet', condition, v) + end + end + + + function m.entryPointSymbol(cfg) + if cfg.entrypoint then + m.element("EntryPointSymbol", nil, cfg.entrypoint) + else + if (cfg.kind == premake.CONSOLEAPP or cfg.kind == premake.WINDOWEDAPP) and + not cfg.flags.WinMain and + cfg.clr == p.OFF and + cfg.system ~= p.XBOX360 + then + m.element("EntryPointSymbol", nil, "mainCRTStartup") + end + end + end + + + function m.exceptionHandling(cfg, condition) + if cfg.exceptionhandling == p.OFF then + m.element("ExceptionHandling", condition, "false") + elseif cfg.exceptionhandling == "SEH" then + m.element("ExceptionHandling", condition, "Async") + end + end + + + function m.excludedFromBuild(filecfg, condition) + if not filecfg or filecfg.flags.ExcludeFromBuild then + m.element("ExcludedFromBuild", condition, "true") + end + end + + + function m.extensionsToDeleteOnClean(cfg) + if #cfg.cleanextensions > 0 then + local value = table.implode(cfg.cleanextensions, "*", ";", "") + m.element("ExtensionsToDeleteOnClean", nil, value .. "$(ExtensionsToDeleteOnClean)") + end + end + + + function m.fileType(cfg, file) + m.element("FileType", nil, "Document") + end + + + function m.floatingPointModel(cfg) + if cfg.floatingpoint and cfg.floatingpoint ~= "Default" then + m.element("FloatingPointModel", nil, cfg.floatingpoint) + end + end + + + function m.floatingPointExceptions(cfg) + if cfg.floatingpointexceptions ~= nil then + if cfg.floatingpointexceptions then + m.element("FloatingPointExceptions", nil, "true") + else + m.element("FloatingPointExceptions", nil, "false") + end + end + end + + + function m.inlineFunctionExpansion(cfg) + if cfg.inlining then + local types = { + Default = "Default", + Disabled = "Disabled", + Explicit = "OnlyExplicitInline", + Auto = "AnySuitable", + } + m.element("InlineFunctionExpansion", nil, types[cfg.inlining]) + end + end + + + function m.forceIncludes(cfg, condition) + if #cfg.forceincludes > 0 then + local includes = vstudio.path(cfg, cfg.forceincludes) + if #includes > 0 then + m.element("ForcedIncludeFiles", condition, table.concat(includes, ';')) + end + end + if #cfg.forceusings > 0 then + local usings = vstudio.path(cfg, cfg.forceusings) + if #usings > 0 then + m.element("ForcedUsingFiles", condition, table.concat(usings, ';')) + end + end + end + + + function m.fullProgramDatabaseFile(cfg) + if _ACTION >= "vs2015" and cfg.symbols == "FastLink" then + m.element("FullProgramDatabaseFile", nil, "true") + end + end + + + function m.functionLevelLinking(cfg) + if cfg.functionlevellinking ~= nil then + if cfg.functionlevellinking then + m.element("FunctionLevelLinking", nil, "true") + else + m.element("FunctionLevelLinking", nil, "false") + end + elseif config.isOptimizedBuild(cfg) then + m.element("FunctionLevelLinking", nil, "true") + end + end + + + function m.generateDebugInformation(cfg) + local lookup = {} + if _ACTION >= "vs2017" then + lookup[p.ON] = "true" + lookup[p.OFF] = "false" + lookup["FastLink"] = "DebugFastLink" + lookup["Full"] = "DebugFull" + elseif _ACTION == "vs2015" then + lookup[p.ON] = "true" + lookup[p.OFF] = "false" + lookup["FastLink"] = "DebugFastLink" + lookup["Full"] = "true" + else + lookup[p.ON] = "true" + lookup[p.OFF] = "false" + lookup["FastLink"] = "true" + lookup["Full"] = "true" + end + + local value = lookup[cfg.symbols] + if value then + m.element("GenerateDebugInformation", nil, value) + end + end + + + function m.generateManifest(cfg) + if cfg.flags.NoManifest then + m.element("GenerateManifest", nil, "false") + end + end + + + function m.generateMapFile(cfg) + if cfg.flags.Maps then + m.element("GenerateMapFile", nil, "true") + end + end + + + function m.ignoreDefaultLibraries(cfg) + if #cfg.ignoredefaultlibraries > 0 then + local ignored = cfg.ignoredefaultlibraries + for i = 1, #ignored do + -- Add extension if required + if not p.tools.msc.getLibraryExtensions()[ignored[i]:match("[^.]+$")] then + ignored[i] = path.appendextension(ignored[i], ".lib") + end + end + + m.element("IgnoreSpecificDefaultLibraries", condition, table.concat(ignored, ';')) + end + end + + + function m.ignoreWarnDuplicateFilename(prj) + -- VS 2013 warns on duplicate file names, even those files which are + -- contained in different, mututally exclusive configurations. See: + -- http://connect.microsoft.com/VisualStudio/feedback/details/797460/incorrect-warning-msb8027-reported-for-files-excluded-from-build + -- Premake already adds unique object names to conflicting file names, so + -- just go ahead and disable that warning. + if _ACTION > "vs2012" then + m.element("IgnoreWarnCompileDuplicatedFilename", nil, "true") + end + end + + + function m.ignoreImportLibrary(cfg) + if cfg.kind == p.SHAREDLIB and cfg.flags.NoImportLib then + m.element("IgnoreImportLibrary", nil, "true") + end + end + + + function m.imageXex(cfg) + if cfg.system == p.XBOX360 then + p.push('') + if cfg.configfile then + m.element("ConfigurationFile", nil, "%s", cfg.configfile) + else + p.w('') + p.w('') + end + p.w('') + p.w('') + p.pop('') + end + end + + + function m.imageXexOutput(cfg) + if cfg.system == p.XBOX360 then + m.element("ImageXexOutput", nil, "%s", "$(OutDir)$(TargetName).xex") + end + end + + + function m.importLanguageTargets(prj) + p.w('') + end + + m.elements.importExtensionTargets = function(prj) + return { + m.importGroupTargets, + m.importRuleTargets, + m.importNuGetTargets, + m.importBuildCustomizationsTargets + } + end + + function m.importExtensionTargets(prj) + p.push('') + p.callArray(m.elements.importExtensionTargets, prj) + p.pop('') + end + + function m.importGroupTargets(prj) + local groups = m.categorizeSources(prj) + for _, group in ipairs(groups) do + if group.category.emitExtensionTargets then + group.category.emitExtensionTargets(prj, group) + end + end + end + + function m.importRuleTargets(prj) + for i = 1, #prj.rules do + local rule = p.global.getRule(prj.rules[i]) + local loc = vstudio.path(prj, p.filename(rule, ".targets")) + p.x('', loc) + end + end + + local function nuGetTargetsFile(prj, package) + return p.vstudio.path(prj, p.filename(prj.solution, string.format("packages\\%s\\build\\native\\%s.targets", vstudio.nuget2010.packageName(package), vstudio.nuget2010.packageId(package)))) + end + + function m.importNuGetTargets(prj) + for i = 1, #prj.nuget do + local targetsFile = nuGetTargetsFile(prj, prj.nuget[i]) + p.x('', targetsFile, targetsFile) + end + end + + function m.importBuildCustomizationsTargets(prj) + for i, build in ipairs(prj.buildcustomizations) do + p.w('', path.translate(build)) + end + end + + + + function m.ensureNuGetPackageBuildImports(prj) + if #prj.nuget > 0 then + p.push('') + p.push('') + p.x('This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.') + p.pop('') + + for i = 1, #prj.nuget do + local targetsFile = nuGetTargetsFile(prj, prj.nuget[i]) + p.x('', targetsFile, targetsFile) + end + p.pop('') + end + end + + + + function m.importDefaultProps(prj) + p.w('') + end + + + + function m.importLanguageSettings(prj) + p.w('') + end + + m.elements.importExtensionSettings = function(prj) + return { + m.importGroupSettings, + m.importRuleSettings, + m.importBuildCustomizationsProps + } + end + + function m.importExtensionSettings(prj) + p.push('') + p.callArray(m.elements.importExtensionSettings, prj) + p.pop('') + end + + + function m.importGroupSettings(prj) + local groups = m.categorizeSources(prj) + for _, group in ipairs(groups) do + if group.category.emitExtensionSettings then + group.category.emitExtensionSettings(prj, group) + end + end + end + + + function m.importRuleSettings(prj) + for i = 1, #prj.rules do + local rule = p.global.getRule(prj.rules[i]) + local loc = vstudio.path(prj, p.filename(rule, ".props")) + p.x('', loc) + end + end + + + function m.importBuildCustomizationsProps(prj) + for i, build in ipairs(prj.buildcustomizations) do + p.w('', path.translate(build)) + end + end + + + + function m.importLibrary(cfg) + if cfg.kind == p.SHAREDLIB then + m.element("ImportLibrary", nil, "%s", path.translate(cfg.linktarget.relpath)) + end + end + + + function m.includePath(cfg) + local dirs = vstudio.path(cfg, cfg.sysincludedirs) + if #dirs > 0 then + m.element("IncludePath", nil, "%s;$(IncludePath)", table.concat(dirs, ";")) + end + end + + + function m.intDir(cfg) + local objdir = vstudio.path(cfg, cfg.objdir) + m.element("IntDir", nil, "%s\\", objdir) + end + + + function m.intrinsicFunctions(cfg) + if cfg.intrinsics ~= nil then + if cfg.intrinsics then + m.element("IntrinsicFunctions", nil, "true") + else + m.element("IntrinsicFunctions", nil, "false") + end + elseif config.isOptimizedBuild(cfg) then + m.element("IntrinsicFunctions", nil, "true") + end + end + + + function m.keyword(prj) + -- try to determine what kind of targets we're building here + local isWin, isManaged, isMakefile + for cfg in project.eachconfig(prj) do + if cfg.system == p.WINDOWS then + isWin = true + end + if cfg.clr ~= p.OFF then + isManaged = true + end + if vstudio.isMakefile(cfg) then + isMakefile = true + end + end + + if isWin then + if isMakefile then + m.element("Keyword", nil, "MakeFileProj") + else + if isManaged or m.isClrMixed(prj) then + m.targetFramework(prj) + end + if isManaged then + m.element("Keyword", nil, "ManagedCProj") + else + m.element("Keyword", nil, "Win32Proj") + end + m.element("RootNamespace", nil, "%s", prj.name) + end + end + end + + + function m.libraryPath(cfg) + local dirs = vstudio.path(cfg, cfg.syslibdirs) + if #dirs > 0 then + m.element("LibraryPath", nil, "%s;$(LibraryPath)", table.concat(dirs, ";")) + end + end + + + + function m.linkIncremental(cfg) + if cfg.kind ~= p.STATICLIB then + m.element("LinkIncremental", nil, "%s", tostring(config.canLinkIncremental(cfg))) + end + end + + + function m.linkLibraryDependencies(cfg, explicit) + -- Left to its own devices, VS will happily link against a project dependency + -- that has been excluded from the build. As a workaround, disable dependency + -- linking and list all siblings explicitly + if explicit then + p.push('') + m.element("LinkLibraryDependencies", nil, "false") + p.pop('') + end + end + + + function m.minimalRebuild(cfg) + if config.isOptimizedBuild(cfg) or + cfg.flags.NoMinimalRebuild or + cfg.flags.MultiProcessorCompile or + cfg.debugformat == p.C7 + then + m.element("MinimalRebuild", nil, "false") + end + end + + + function m.moduleDefinitionFile(cfg) + local df = config.findfile(cfg, ".def") + if df then + m.element("ModuleDefinitionFile", nil, "%s", df) + end + end + + + function m.multiProcessorCompilation(cfg) + if cfg.flags.MultiProcessorCompile then + m.element("MultiProcessorCompilation", nil, "true") + end + end + + + function m.nmakeBuildCommands(cfg) + m.nmakeCommandLine(cfg, cfg.buildcommands, "Build") + end + + + function m.nmakeCleanCommands(cfg) + m.nmakeCommandLine(cfg, cfg.cleancommands, "Clean") + end + + + function m.nmakeCommandLine(cfg, commands, phase) + if #commands > 0 then + commands = os.translateCommands(commands, p.WINDOWS) + commands = table.concat(p.esc(commands), p.eol()) + p.w('%s', phase, commands, phase) + end + end + + + function m.nmakeIncludeDirs(cfg) + if cfg.kind ~= p.NONE and #cfg.includedirs > 0 then + local dirs = vstudio.path(cfg, cfg.includedirs) + if #dirs > 0 then + m.element("NMakeIncludeSearchPath", nil, "%s", table.concat(dirs, ";")) + end + end + end + + + function m.nmakeOutDirs(cfg) + if vstudio.isMakefile(cfg) then + m.outDir(cfg) + m.intDir(cfg) + end + end + + + function m.nmakeOutput(cfg) + m.element("NMakeOutput", nil, "$(OutDir)%s", cfg.buildtarget.name) + end + + + function m.nmakePreprocessorDefinitions(cfg) + if cfg.kind ~= p.NONE and #cfg.defines > 0 then + local defines = table.concat(cfg.defines, ";") + defines = p.esc(defines) .. ";$(NMakePreprocessorDefinitions)" + m.element('NMakePreprocessorDefinitions', nil, defines) + end + end + + + function m.nmakeRebuildCommands(cfg) + m.nmakeCommandLine(cfg, cfg.rebuildcommands, "ReBuild") + end + + + function m.objectFileName(fcfg) + if fcfg.objname ~= fcfg.basename then + m.element("ObjectFileName", m.condition(fcfg.config), "$(IntDir)\\%s.obj", fcfg.objname) + end + end + + + + function m.omitDefaultLib(cfg) + if cfg.flags.OmitDefaultLibrary then + m.element("OmitDefaultLibName", nil, "true") + end + end + + + + function m.omitFramePointers(cfg) + if cfg.flags.NoFramePointer then + m.element("OmitFramePointers", nil, "true") + end + end + + + function m.optimizeReferences(cfg) + if config.isOptimizedBuild(cfg) then + m.element("EnableCOMDATFolding", nil, "true") + m.element("OptimizeReferences", nil, "true") + end + end + + + function m.optimization(cfg, condition) + local map = { Off="Disabled", On="Full", Debug="Disabled", Full="Full", Size="MinSpace", Speed="MaxSpeed" } + local value = map[cfg.optimize] + if value or not condition then + m.element('Optimization', condition, value or "Disabled") + end + end + + + function m.outDir(cfg) + local outdir = vstudio.path(cfg, cfg.buildtarget.directory) + m.element("OutDir", nil, "%s\\", outdir) + end + + + function m.outputFile(cfg) + if cfg.system == p.XBOX360 then + m.element("OutputFile", nil, "$(OutDir)%s", cfg.buildtarget.name) + end + end + + + function m.executablePath(cfg) + local dirs = vstudio.path(cfg, cfg.bindirs) + if #dirs > 0 then + m.element("ExecutablePath", nil, "%s;$(ExecutablePath)", table.concat(dirs, ";")) + end + end + + + function m.platformToolset(cfg) + local tool, version = p.config.toolset(cfg) + if not version then + local action = p.action.current() + version = action.vstudio.platformToolset + end + if version then + if cfg.kind == p.NONE or cfg.kind == p.MAKEFILE then + if p.config.hasFile(cfg, path.iscppfile) then + m.element("PlatformToolset", nil, version) + end + else + m.element("PlatformToolset", nil, version) + end + end + end + + + function m.precompiledHeader(cfg, condition) + prjcfg, filecfg = p.config.normalize(cfg) + if filecfg then + if prjcfg.pchsource == filecfg.abspath and not prjcfg.flags.NoPCH then + m.element('PrecompiledHeader', condition, 'Create') + elseif filecfg.flags.NoPCH then + m.element('PrecompiledHeader', condition, 'NotUsing') + end + else + if not prjcfg.flags.NoPCH and prjcfg.pchheader then + m.element("PrecompiledHeader", nil, "Use") + m.element("PrecompiledHeaderFile", nil, "%s", prjcfg.pchheader) + else + m.element("PrecompiledHeader", nil, "NotUsing") + end + end + end + + + function m.preprocessorDefinitions(cfg, defines, escapeQuotes, condition) + if #defines > 0 then + defines = table.concat(defines, ";") + if escapeQuotes then + defines = defines:gsub('"', '\\"') + end + defines = p.esc(defines) .. ";%%(PreprocessorDefinitions)" + m.element('PreprocessorDefinitions', condition, defines) + end + end + + + function m.undefinePreprocessorDefinitions(cfg, undefines, escapeQuotes, condition) + if #undefines > 0 then + undefines = table.concat(undefines, ";") + if escapeQuotes then + undefines = undefines:gsub('"', '\\"') + end + undefines = p.esc(undefines) .. ";%%(UndefinePreprocessorDefinitions)" + m.element('UndefinePreprocessorDefinitions', condition, undefines) + end + end + + + function m.programDatabaseFile(cfg) + if cfg.symbolspath and cfg.symbols == p.ON and cfg.debugformat ~= "c7" then + m.element("ProgramDatabaseFile", nil, p.project.getrelative(cfg.project, cfg.symbolspath)) + end + end + + + function m.projectGuid(prj) + m.element("ProjectGuid", nil, "{%s}", prj.uuid) + end + + + function m.projectName(prj) + if prj.name ~= prj.filename then + m.element("ProjectName", nil, "%s", prj.name) + end + end + + + function m.propertyGroup(cfg, label) + local cond + if cfg then + cond = string.format(' %s', m.condition(cfg)) + end + + if label then + label = string.format(' Label="%s"', label) + end + + p.push('', cond or "", label or "") + end + + + + function m.propertySheets(cfg) + p.push('', m.condition(cfg)) + p.w('') + p.pop('') + end + + + function m.propertySheetGroup(prj) + for cfg in project.eachconfig(prj) do + m.propertySheets(cfg) + end + end + + + function m.referenceCopyLocalSatelliteAssemblies(prj, ref) + m.element("CopyLocalSatelliteAssemblies", nil, "false") + end + + + function m.referenceLinkLibraryDependencies(prj, ref) + m.element("LinkLibraryDependencies", nil, "true") + end + + + function m.referenceOutputAssembly(prj, ref) + m.element("ReferenceOutputAssembly", nil, "true") + end + + + function m.referencePrivate(prj, ref) + m.element("Private", nil, "true") + end + + + function m.referenceProject(prj, ref) + m.element("Project", nil, "{%s}", ref.uuid) + end + + + function m.referenceUseLibraryDependences(prj, ref) + m.element("UseLibraryDependencyInputs", nil, "false") + end + + + function m.resourceAdditionalIncludeDirectories(cfg) + m.additionalIncludeDirectories(cfg, table.join(cfg.includedirs, cfg.resincludedirs)) + end + + + function m.resourcePreprocessorDefinitions(cfg) + local defines = table.join(cfg.defines, cfg.resdefines) + if cfg.exceptionhandling == p.OFF and _ACTION >= "vs2013" then + table.insert(defines, "_HAS_EXCEPTIONS=0") + end + m.preprocessorDefinitions(cfg, defines, true) + end + + + function m.runtimeLibrary(cfg) + local runtimes = { + StaticDebug = "MultiThreadedDebug", + StaticRelease = "MultiThreaded", + } + local runtime = runtimes[config.getruntime(cfg)] + if runtime then + m.element("RuntimeLibrary", nil, runtime) + end + end + + function m.callingConvention(cfg) + if cfg.callingconvention then + m.element("CallingConvention", nil, cfg.callingconvention) + end + end + + function m.runtimeTypeInfo(cfg) + if cfg.rtti == p.OFF and cfg.clr == p.OFF then + m.element("RuntimeTypeInfo", nil, "false") + elseif cfg.rtti == p.ON then + m.element("RuntimeTypeInfo", nil, "true") + end + end + + function m.bufferSecurityCheck(cfg) + local tool, toolVersion = p.config.toolset(cfg) + if cfg.flags.NoBufferSecurityCheck or (toolVersion and toolVersion:startswith("LLVM-vs")) then + m.element("BufferSecurityCheck", nil, "false") + end + end + + function m.stringPooling(cfg) + if cfg.stringpooling ~= nil then + if cfg.stringpooling then + m.element("StringPooling", nil, "true") + else + m.element("StringPooling", nil, "false") + end + elseif config.isOptimizedBuild(cfg) then + m.element("StringPooling", nil, "true") + end + end + + + function m.subSystem(cfg) + if cfg.system ~= p.XBOX360 then + local subsystem = iif(cfg.kind == p.CONSOLEAPP, "Console", "Windows") + m.element("SubSystem", nil, subsystem) + end + end + + + function m.targetExt(cfg) + local ext = cfg.buildtarget.extension + if ext ~= "" then + m.element("TargetExt", nil, "%s", ext) + else + p.w('') + p.w('') + end + end + + + function m.targetMachine(cfg) + -- If a static library project contains a resource file, VS will choke with + -- "LINK : warning LNK4068: /MACHINE not specified; defaulting to X86" + local targetmachine = { + x86 = "MachineX86", + x86_64 = "MachineX64", + } + if cfg.kind == p.STATICLIB and config.hasFile(cfg, path.isresourcefile) then + local value = targetmachine[cfg.architecture] + if value ~= nil then + m.element("TargetMachine", nil, '%s', value) + end + end + end + + + function m.targetName(cfg) + m.element("TargetName", nil, "%s%s", cfg.buildtarget.prefix, cfg.buildtarget.basename) + end + + + function m.targetPlatformVersion(prj) + local min = project.systemversion(prj) + if min ~= nil and _ACTION >= "vs2015" then + m.element("WindowsTargetPlatformVersion", nil, min) + end + end + + + function m.treatLinkerWarningAsErrors(cfg) + if cfg.flags.FatalLinkWarnings then + local el = iif(cfg.kind == p.STATICLIB, "Lib", "Linker") + m.element("Treat" .. el .. "WarningAsErrors", nil, "true") + end + end + + + function m.treatWChar_tAsBuiltInType(cfg) + local map = { On = "true", Off = "false" } + local value = map[cfg.nativewchar] + if value then + m.element("TreatWChar_tAsBuiltInType", nil, value) + end + end + + + function m.treatWarningAsError(cfg) + if cfg.flags.FatalCompileWarnings and cfg.warnings ~= p.OFF then + m.element("TreatWarningAsError", nil, "true") + end + end + + + function m.disableSpecificWarnings(cfg, condition) + if #cfg.disablewarnings > 0 then + local warnings = table.concat(cfg.disablewarnings, ";") + warnings = p.esc(warnings) .. ";%%(DisableSpecificWarnings)" + m.element('DisableSpecificWarnings', condition, warnings) + end + end + + + function m.treatSpecificWarningsAsErrors(cfg, condition) + if #cfg.fatalwarnings > 0 then + local fatal = table.concat(cfg.fatalwarnings, ";") + fatal = p.esc(fatal) .. ";%%(TreatSpecificWarningsAsErrors)" + m.element('TreatSpecificWarningsAsErrors', condition, fatal) + end + end + + + function m.useDebugLibraries(cfg) + local runtime = config.getruntime(cfg) + m.element("UseDebugLibraries", nil, tostring(runtime:endswith("Debug"))) + end + + + function m.useOfMfc(cfg) + if cfg.flags.MFC then + m.element("UseOfMfc", nil, iif(cfg.flags.StaticRuntime, "Static", "Dynamic")) + end + end + + function m.useOfAtl(cfg) + if cfg.atl then + m.element("UseOfATL", nil, cfg.atl) + end + end + + + + function m.userMacros(cfg) + p.w('') + end + + + + function m.warningLevel(cfg) + local map = { Off = "TurnOffAllWarnings", Extra = "Level4" } + m.element("WarningLevel", nil, "%s", map[cfg.warnings] or "Level3") + end + + + + function m.xmlDeclaration() + p.xmlUtf8() + end + + + +--------------------------------------------------------------------------- +-- +-- Support functions +-- +--------------------------------------------------------------------------- + +-- +-- Format and return a Visual Studio Condition attribute. +-- + + function m.condition(cfg) + return string.format('Condition="\'$(Configuration)|$(Platform)\'==\'%s\'"', p.esc(vstudio.projectConfig(cfg))) + end + + +-- +-- Output an individual project XML element, with an optional configuration +-- condition. +-- +-- @param depth +-- How much to indent the element. +-- @param name +-- The element name. +-- @param condition +-- An optional configuration condition, formatted with vc2010.condition(). +-- @param value +-- The element value, which may contain printf formatting tokens. +-- @param ... +-- Optional additional arguments to satisfy any tokens in the value. +-- + + function m.element(name, condition, value, ...) + if select('#',...) == 0 then + value = p.esc(value) + end + + local format + if condition then + format = string.format('<%s %s>%s', name, condition, value, name) + else + format = string.format('<%s>%s', name, value, name) + end + + p.x(format, ...) + end diff --git a/src/base/config.lua b/src/base/config.lua index 136a05cf..a011ec75 100755 --- a/src/base/config.lua +++ b/src/base/config.lua @@ -192,7 +192,7 @@ -- if the configuration target is a DLL, and an import library -- is provided, change the kind as import libraries are static. local kind = cfg.kind - if project.iscpp(cfg.project) then + if project.isnative(cfg.project) then if cfg.system == premake.WINDOWS and kind == premake.SHAREDLIB and not cfg.flags.NoImportLib then kind = premake.STATICLIB end diff --git a/src/base/languages.lua b/src/base/languages.lua new file mode 100644 index 00000000..c130432f --- /dev/null +++ b/src/base/languages.lua @@ -0,0 +1,68 @@ +--- +-- languages.lua +-- Language helpers. +-- Copyright (c) 2002-2015 Jason Perkins and the Premake project +--- + + premake.languages = {} + local p = premake + local languages = p.languages + + +--- +-- List of supported C languages. +--- + languages.c = { + "C", + "C89", + "C90", + "C99", + "C11", + "gnu89", + "gnu90", + "gnu99", + "gnu11", + } + + function languages.isc(value) + return table.contains(languages.c, value) + end + +--- +-- List of supported C++ languages. +--- + languages.cpp = { + "C++", + "C++98", + "C++11", + "C++14", + "C++17", + "gnu++98", + "gnu++11", + "gnu++14", + "gnu++17", + } + + function languages.iscpp(value) + return table.contains(languages.cpp, value) + end + +--- +-- List of supported dotnet languages. +--- + languages.dotnet = { + "C#" + } + + function languages.isdotnet(value) + return table.contains(languages.dotnet, value) + end + +--- +-- Combined list of all supported languages. +--- + languages.all = table.join( + languages.c, + languages.cpp, + languages.dotnet + ) diff --git a/src/base/oven.lua b/src/base/oven.lua index eb1ac786..a781ac91 100644 --- a/src/base/oven.lua +++ b/src/base/oven.lua @@ -181,7 +181,7 @@ end -- generated files might screw up the object sequences. - if prj.hasGeneratedFiles and p.project.iscpp(prj) then + if prj.hasGeneratedFiles and p.project.isnative(prj) then oven.assignObjectSequences(prj) end end @@ -278,7 +278,7 @@ -- to do this up front to make sure the sequence numbers are the same for -- all the tools, even they reorder the source file list. - if p.project.iscpp(self) then + if p.project.isnative(self) then oven.assignObjectSequences(self) end end diff --git a/src/base/project.lua b/src/base/project.lua index d5c81783..48ae00bb 100755 --- a/src/base/project.lua +++ b/src/base/project.lua @@ -440,40 +440,40 @@ end --- --- Returns true if the project uses the C (and not C++) language. --- - - function project.isc(prj) - return prj.language == premake.C - end - - - --- --- Returns true if the project uses a C/C++ language. --- - - function project.iscpp(prj) - return prj.language == premake.C or prj.language == premake.CPP - end - - -- -- Returns true if the project uses a .NET language. -- function project.isdotnet(prj) - return prj.language == premake.CSHARP + return p.languages.isdotnet(prj.language) end -- --- Returns true if the project uses a native language. +-- Returns true if the project uses a cpp language. -- + function project.isc(prj) + return p.languages.isc(prj.language) + end + + +-- +-- Returns true if the project uses a cpp language. +-- + + function project.iscpp(prj) + return p.languages.iscpp(prj.language) + end + + +-- +-- Returns true if the project has uses any 'native' languages. +-- which is basically anything other then .net at this point. +-- modules like the dlang should overload this to add 'project.isd(prj)' to it. +-- function project.isnative(prj) - return project.iscpp(prj) + return project.isc(prj) or project.iscpp(prj) end diff --git a/src/base/validation.lua b/src/base/validation.lua index f2729f1a..8ace733b 100644 --- a/src/base/validation.lua +++ b/src/base/validation.lua @@ -163,30 +163,34 @@ function m.actionSupportsKind(prj) if not p.action.supports(prj.kind) then - p.warn("unsupported kind '%s' used for project '%s'", prj.kind, prj.name) + p.warn("Unsupported kind '%s' used for project '%s'", prj.kind, prj.name) end end function m.actionSupportsLanguage(prj) if not p.action.supports(prj.language) then - p.warn("unsupported language '%s' used for project '%s'", prj.language, prj.name) + p.warn("Unsupported language '%s' used for project '%s'", prj.language, prj.name) end end function m.configHasKind(cfg) if not cfg.kind then - p.error("project '%s' needs a kind in configuration '%s'", cfg.project.name, cfg.name) + p.error("Project '%s' needs a kind in configuration '%s'", cfg.project.name, cfg.name) end end function m.configSupportsKind(cfg) + if not p.action.supports(cfg.kind) then + p.warn("Unsupported kind '%s' used in configuration '%s'", cfg.kind, cfg.name) + end + -- makefile configuration can only appear in C++ projects; this is the -- default now, so should only be a problem if overridden. - if (cfg.kind == p.MAKEFILE or cfg.kind == p.NONE) and not p.project.iscpp(cfg.project) then - p.error("project '%s' uses %s kind in configuration '%s'; language must be C++", cfg.project.name, cfg.kind, cfg.name) + if (cfg.kind == p.MAKEFILE or cfg.kind == p.NONE) and p.project.isdotnet(cfg.project) then + p.error("Project '%s' uses '%s' kind in configuration '%s'; language must not be C#", cfg.project.name, cfg.kind, cfg.name) end end diff --git a/src/tools/gcc.lua b/src/tools/gcc.lua index 8dee6541..65159700 100644 --- a/src/tools/gcc.lua +++ b/src/tools/gcc.lua @@ -91,6 +91,16 @@ ["C99"] = "-std=gnu99", ["C11"] = "-std=gnu11", }, + language = { + ["C89"] = "-std=c89", + ["C90"] = "-std=c90", + ["C99"] = "-std=c99", + ["C11"] = "-std=c11", + ["gnu89"] = "-std=gnu89", + ["gnu90"] = "-std=gnu90", + ["gnu99"] = "-std=gnu99", + ["gnu11"] = "-std=gnu11", + } } function gcc.getcflags(cfg) @@ -129,6 +139,16 @@ ["C++11"] = "-std=c++11", ["C++14"] = "-std=c++14", }, + language = { + ["C++98"] = "-std=c++98", + ["C++11"] = "-std=c++11", + ["C++14"] = "-std=c++14", + ["C++17"] = "-std=c++17", + ["gnu++98"] = "-std=gnu++98", + ["gnu++11"] = "-std=gnu++11", + ["gnu++14"] = "-std=gnu++14", + ["gnu++17"] = "-std=gnu++17", + }, rtti = { Off = "-fno-rtti" } From 7b55321473135f04976fd3543e2a7b4ba14a5043 Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Fri, 14 Apr 2017 03:07:20 +1000 Subject: [PATCH 15/59] Added BSD support --- Bootstrap.mak | 7 +++++++ contrib/curl/lib/curl_setup.h | 4 ++++ contrib/curl/premake5.lua | 5 +++-- contrib/libzip/premake5.lua | 2 +- src/host/premake.c | 15 +++++++++++++++ 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/Bootstrap.mak b/Bootstrap.mak index d1eebf97..d089654b 100644 --- a/Bootstrap.mak +++ b/Bootstrap.mak @@ -65,6 +65,13 @@ linux: $(SRC) ./build/bootstrap/premake_bootstrap --to=build/bootstrap gmake $(MAKE) -C build/bootstrap -j`getconf _NPROCESSORS_ONLN` +bsd: $(SRC) + mkdir -p build/bootstrap + $(CC) -o build/bootstrap/premake_bootstrap -DPREMAKE_NO_BUILTIN_SCRIPTS -DLUA_USE_POSIX -DLUA_USE_DLOPEN -I"$(LUA_DIR)" $? -lm + ./build/bootstrap/premake_bootstrap embed + ./build/bootstrap/premake_bootstrap --to=build/bootstrap gmake + $(MAKE) -C build/bootstrap -j`getconf _NPROCESSORS_ONLN` + windows-base: $(SRC) if not exist build\bootstrap (mkdir build\bootstrap) cl /Fo.\build\bootstrap\ /Fe.\build\bootstrap\premake_bootstrap.exe /DPREMAKE_NO_BUILTIN_SCRIPTS /I"$(LUA_DIR)" user32.lib ole32.lib advapi32.lib $** diff --git a/contrib/curl/lib/curl_setup.h b/contrib/curl/lib/curl_setup.h index 93a59ab2..19db0aea 100644 --- a/contrib/curl/lib/curl_setup.h +++ b/contrib/curl/lib/curl_setup.h @@ -82,6 +82,10 @@ # include "config-linux.h" #endif +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) +# include "config-linux.h" +#endif + #ifdef __APPLE__ && __MACH__ # include "config-osx.h" #endif diff --git a/contrib/curl/premake5.lua b/contrib/curl/premake5.lua index 77be654d..ef03af83 100644 --- a/contrib/curl/premake5.lua +++ b/contrib/curl/premake5.lua @@ -15,7 +15,7 @@ project "curl-lib" "**.h", "**.c" } - + filter { "system:windows" } defines { "USE_SCHANNEL", "USE_WINDOWS_SSPI" } @@ -25,7 +25,7 @@ project "curl-lib" filter { "system:not windows", "system:not macosx" } defines { "USE_MBEDTLS" } - filter { "system:linux" } + filter { "system:linux or bsd" } defines { "CURL_HIDDEN_SYMBOLS" } -- find the location of the ca bundle @@ -35,6 +35,7 @@ project "curl-lib" "/etc/pki/tls/certs/ca-bundle.crt", "/usr/share/ssl/certs/ca-bundle.crt", "/usr/local/share/certs/ca-root.crt", + "/usr/local/share/certs/ca-root-nss.crt", "/etc/ssl/cert.pem" } do if os.isfile(f) then ca = f diff --git a/contrib/libzip/premake5.lua b/contrib/libzip/premake5.lua index d8b67b55..62163c81 100644 --- a/contrib/libzip/premake5.lua +++ b/contrib/libzip/premake5.lua @@ -11,7 +11,7 @@ project "zip-lib" "**.c" } - filter "system:linux" + filter "system:linux or bsd" defines { "HAVE_SSIZE_T_LIBZIP", "HAVE_CONFIG_H" } filter "system:windows" diff --git a/src/host/premake.c b/src/host/premake.c index 63e21583..8b03b2f0 100644 --- a/src/host/premake.c +++ b/src/host/premake.c @@ -13,6 +13,10 @@ #include #endif +#if PLATFORM_BSD +#include +#include +#endif #define ERROR_MESSAGE "Error: %s\n" @@ -262,6 +266,17 @@ int premake_locate_executable(lua_State* L, const char* argv0) int len = readlink("/proc/curproc/file", buffer, PATH_MAX - 1); if (len < 0) len = readlink("/proc/curproc/exe", buffer, PATH_MAX - 1); + if (len < 0) + { + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + size_t cb = sizeof(buffer); + sysctl(mib, 4, buffer, &cb, NULL, 0); + len = (int)cb; + } if (len > 0) { buffer[len] = 0; From d1f5c333b00d7fee85f81c03ae03c0b976f74899 Mon Sep 17 00:00:00 2001 From: Jason Perkins Date: Thu, 13 Apr 2017 15:37:49 -0400 Subject: [PATCH 16/59] Clean up the deprecated APIs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add "Use … instead." messages to any deprecations that did not have one - Change deprecation date on APIs without a message to current date - Remove APIs that have been deprecated for more than a year h/t to @samsinsane for original PR on which this is based (#741) --- modules/xcode/tests/test_xcode_project.lua | 12 +- modules/xcode/xcode_common.lua | 6 +- premake5.lua | 3 +- src/_premake_init.lua | 151 ++++++++++----------- src/base/api.lua | 6 +- 5 files changed, 83 insertions(+), 95 deletions(-) diff --git a/modules/xcode/tests/test_xcode_project.lua b/modules/xcode/tests/test_xcode_project.lua index 2dd2b939..1f13f90b 100644 --- a/modules/xcode/tests/test_xcode_project.lua +++ b/modules/xcode/tests/test_xcode_project.lua @@ -1125,8 +1125,7 @@ end - function suite.XCBuildConfigurationProject_OnOptimize() - --flags { "Optimize" } + function suite.XCBuildConfigurationProject_OnOptimizeSize() optimize "Size" prepare() xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) @@ -1153,7 +1152,7 @@ function suite.XCBuildConfigurationProject_OnOptimizeSpeed() - flags { "OptimizeSpeed" } + optimize "Speed" prepare() xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) test.capture [[ @@ -1411,7 +1410,6 @@ function suite.XCBuildConfigurationProject_OnExtraWarnings() - --flags { "ExtraWarnings" } warnings "Extra" prepare() xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) @@ -1495,7 +1493,7 @@ function suite.XCBuildConfigurationProject_OnFloatStrict() - flags { "FloatStrict" } + floatingpoint "Strict" prepare() xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) test.capture [[ @@ -1524,7 +1522,7 @@ function suite.XCBuildConfigurationProject_OnNoEditAndContinue() - flags { "NoEditAndContinue" } + editandcontinue "Off" symbols "On" prepare() xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) @@ -2046,7 +2044,7 @@ function suite.defaultVisibilitySetting_setToNo() end function suite.releaseBuild_onlyDefaultArch_equalsNo() - flags { "Optimize" } + optimize "On" prepare() xcode.XCBuildConfiguration_Project(tr, tr.configs[2]) local str = premake.captured() diff --git a/modules/xcode/xcode_common.lua b/modules/xcode/xcode_common.lua index 53d15d8c..de7cd4de 100644 --- a/modules/xcode/xcode_common.lua +++ b/modules/xcode/xcode_common.lua @@ -1032,7 +1032,7 @@ settings['GCC_ENABLE_CPP_RTTI'] = 'NO' end - if cfg.symbols == p.ON and not cfg.flags.NoEditAndContinue then + if cfg.symbols == p.ON and cfg.editandcontinue ~= "Off" then settings['GCC_ENABLE_FIX_AND_CONTINUE'] = 'YES' end @@ -1095,8 +1095,8 @@ -- build list of "other" C/C++ flags local checks = { - ["-ffast-math"] = cfg.flags.FloatFast, - ["-ffloat-store"] = cfg.flags.FloatStrict, + ["-ffast-math"] = cfg.floatingpoint == "Fast", + ["-ffloat-store"] = cfg.floatingpoint == "Strict", ["-fomit-frame-pointer"] = cfg.flags.NoFramePointer, } diff --git a/premake5.lua b/premake5.lua index fe18913c..d5b23a9d 100644 --- a/premake5.lua +++ b/premake5.lua @@ -94,7 +94,8 @@ configurations { "Release", "Debug" } location ( _OPTIONS["to"] ) - flags { "No64BitChecks", "ExtraWarnings", "StaticRuntime", "MultiProcessorCompile" } + flags { "No64BitChecks", "StaticRuntime", "MultiProcessorCompile" } + warnings "Extra" if not _OPTIONS["no-zlib"] then defines { "PREMAKE_COMPRESSION" } diff --git a/src/_premake_init.lua b/src/_premake_init.lua index c88b61b9..c1a57449 100644 --- a/src/_premake_init.lua +++ b/src/_premake_init.lua @@ -480,7 +480,6 @@ "No64BitChecks", "NoCopyLocal", "NoEditAndContinue", -- DEPRECATED - "NoExceptions", -- DEPRECATED "NoFramePointer", "NoImplicitLink", "NoImportLib", @@ -490,7 +489,6 @@ "NoNativeWChar", -- DEPRECATED "NoPCH", "NoRuntimeChecks", - "NoRTTI", -- DEPRECATED "NoBufferSecurityCheck", "NoWarnings", -- DEPRECATED "OmitDefaultLibrary", @@ -499,13 +497,10 @@ "OptimizeSpeed", -- DEPRECATED "RelativeLinks", "ReleaseRuntime", -- DEPRECATED - "SEH", -- DEPRECATED "ShadowedVariables", "StaticRuntime", "Symbols", -- DEPRECATED "UndefinedIdentifiers", - "Unicode", -- DEPRECATED - "Unsafe", -- DEPRECATED "WinMain", "WPF", "C++11", -- DEPRECATED @@ -1210,9 +1205,9 @@ -- ----------------------------------------------------------------------------- - -- 09 Apr 2013 + -- 13 Apr 2017 - api.deprecateField("buildrule", nil, + api.deprecateField("buildrule", 'Use `buildcommands`, `buildoutputs`, and `buildmessage` instead.', function(value) if value.description then buildmessage(value.description) @@ -1222,83 +1217,119 @@ end) - -- 17 Jun 2013 - - api.deprecateValue("flags", "Component", nil, + api.deprecateValue("flags", "Component", 'Use `buildaction "Component"` instead.', function(value) buildaction "Component" end) - -- 26 Sep 2013 - - api.deprecateValue("flags", { "EnableSSE", "EnableSSE2" }, nil, + api.deprecateValue("flags", "EnableSSE", 'Use `vectorextensions "SSE"` instead.', function(value) - vectorextensions(value:sub(7)) + vectorextensions("SSE") end, function(value) vectorextensions "Default" end) - api.deprecateValue("flags", { "FloatFast", "FloatStrict" }, nil, + api.deprecateValue("flags", "EnableSSE2", 'Use `vectorextensions "SSE2"` instead.', function(value) - floatingpoint(value:sub(6)) + vectorextensions("SSE2") + end, + function(value) + vectorextensions "Default" + end) + + + api.deprecateValue("flags", "FloatFast", 'Use `floatingpoint "Fast"` instead.', + function(value) + floatingpoint("Fast") end, function(value) floatingpoint "Default" end) - api.deprecateValue("flags", { "NativeWChar", "NoNativeWChar" }, nil, + api.deprecateValue("flags", "FloatStrict", 'Use `floatingpoint "Strict"` instead.', function(value) - local map = { NativeWChar = "On", NoNativeWChar = "Off" } - nativewchar(map[value] or "Default") + floatingpoint("Strict") + end, + function(value) + floatingpoint "Default" + end) + + + api.deprecateValue("flags", "NativeWChar", 'Use `nativewchar "On"` instead."', + function(value) + nativewchar("On") end, function(value) nativewchar "Default" end) - api.deprecateValue("flags", { "Optimize", "OptimizeSize", "OptimizeSpeed" }, nil, + api.deprecateValue("flags", "NoNativeWChar", 'Use `nativewchar "Off"` instead."', function(value) - local map = { Optimize = "On", OptimizeSize = "Size", OptimizeSpeed = "Speed" } - optimize (map[value] or "Off") + nativewchar("Off") end, function(value) - optimize "Off" + nativewchar "Default" end) - api.deprecateValue("flags", { "ReleaseRuntime" }, nil, - function(value) - runtime 'Release' - end, - function(value) - end) - api.deprecateValue("flags", { "Optimise", "OptimiseSize", "OptimiseSpeed" }, nil, + api.deprecateValue("flags", "Optimize", 'Use `optimize "On"` instead.', function(value) - local map = { Optimise = "On", OptimiseSize = "Size", OptimiseSpeed = "Speed" } - optimize (map[value] or "Off") + optimize ("On") end, function(value) optimize "Off" end) - api.deprecateValue("flags", { "ExtraWarnings", "NoWarnings" }, nil, + api.deprecateValue("flags", "OptimizeSize", 'Use `optimize "Size"` instead.', function(value) - local map = { ExtraWarnings = "Extra", NoWarnings = "Off" } - warnings (map[value] or "Default") + optimize ("Size") + end, + function(value) + optimize "Off" + end) + + + api.deprecateValue("flags", "OptimizeSpeed", 'Use `optimize "Speed"` instead.', + function(value) + optimize ("Speed") + end, + function(value) + optimize "Off" + end) + + + api.deprecateValue("flags", "ReleaseRuntime", 'Use `runtime "Release"` instead.', + function(value) + runtime "Release" + end, + function(value) + end) + + + api.deprecateValue("flags", "ExtraWarnings", 'Use `warnings "Extra"` instead.', + function(value) + warnings "Extra" end, function(value) warnings "Default" end) - -- 10 Nov 2014 + api.deprecateValue("flags", "NoWarnings", 'Use `warnings "Off"` instead.', + function(value) + warnings "Off" + end, + function(value) + warnings "Default" + end) - api.deprecateValue("flags", "Managed", nil, + api.deprecateValue("flags", "Managed", 'Use `clr "On"` instead.', function(value) clr "On" end, @@ -1307,7 +1338,7 @@ end) - api.deprecateValue("flags", "NoEditAndContinue", nil, + api.deprecateValue("flags", "NoEditAndContinue", 'Use editandcontinue "Off"` instead.', function(value) editandcontinue "Off" end, @@ -1316,49 +1347,6 @@ end) - api.deprecateValue("flags", "NoExceptions", 'Use `exceptionhandling "Off"` instead', - function(value) - exceptionhandling "Off" - end, - function(value) - exceptionhandling "On" - end) - - - api.deprecateValue("flags", "NoRTTI", 'Use `rtti "Off"` instead', - function(value) - rtti "Off" - end, - function(value) - rtti "On" - end) - - api.deprecateValue("flags", "SEH", 'Use `exceptionhandling "SEH"` instead', - function(value) - exceptionhandling "SEH" - end, - function(value) - exceptionhandling "Default" - end) - - api.deprecateValue("flags", "Unsafe", 'Use `clr "Unsafe"` instead', - function(value) - clr "Unsafe" - end, - function(value) - clr "On" - end) - - -- 18 Dec 2015 - - api.deprecateValue("flags", "Unicode", 'Use `characterset "Unicode"` instead', - function(value) - characterset "Unicode" - end, - function(value) - characterset "Default" - end) - -- 21 June 2016 api.deprecateValue("flags", "Symbols", 'Use `symbols "On"` instead', @@ -1378,6 +1366,7 @@ api.deprecateValue("flags", "C99", 'Use `language "C99"` instead', function(value) end, function(value) end) api.deprecateValue("flags", "C11", 'Use `language "C11"` instead', function(value) end, function(value) end) + ----------------------------------------------------------------------------- -- -- Install Premake's default set of command line arguments. diff --git a/src/base/api.lua b/src/base/api.lua index f4f251ce..fb953e32 100755 --- a/src/base/api.lua +++ b/src/base/api.lua @@ -490,7 +490,7 @@ if field.deprecated and type(field.deprecated.handler) == "function" then field.deprecated.handler(value) if field.deprecated.message and api._deprecations ~= "off" then - premake.warnOnce(field.name, "the field %s has been deprecated.\n %s", field.name, field.deprecated.message) + premake.warnOnce(field.name, "the field %s has been deprecated and will be removed.\n %s", field.name, field.deprecated.message) if api._deprecations == "error" then error("deprecation errors enabled", 3) end end end @@ -542,7 +542,7 @@ if handler.remove then handler.remove(value) end if handler.message and api._deprecations ~= "off" then local key = field.name .. "_" .. value - premake.warnOnce(key, "the %s value %s has been deprecated.\n %s", field.name, value, handler.message) + premake.warnOnce(key, "the %s value %s has been deprecated and will be removed.\n %s", field.name, value, handler.message) if api._deprecations == "error" then error { msg="deprecation errors enabled" } end @@ -648,7 +648,7 @@ handler.add(canonical) if handler.message and api._deprecations ~= "off" then local key = field.name .. "_" .. value - premake.warnOnce(key, "the %s value %s has been deprecated.\n %s", field.name, canonical, handler.message) + premake.warnOnce(key, "the %s value %s has been deprecated and will be removed.\n %s", field.name, canonical, handler.message) if api._deprecations == "error" then return nil, "deprecation errors enabled" end From 164fadc8572c7e813b77c9e7835309bd3f9599cb Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Thu, 13 Apr 2017 23:22:19 +1000 Subject: [PATCH 17/59] Properly deprecate WinMain flag --- src/_premake_init.lua | 15 ++++++++++++++- src/actions/vstudio/vs200x_vcproj.lua | 7 ++----- src/actions/vstudio/vs2010_vcxproj.lua | 8 -------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/_premake_init.lua b/src/_premake_init.lua index c1a57449..1e921721 100644 --- a/src/_premake_init.lua +++ b/src/_premake_init.lua @@ -501,7 +501,7 @@ "StaticRuntime", "Symbols", -- DEPRECATED "UndefinedIdentifiers", - "WinMain", + "WinMain", -- DEPRECATED "WPF", "C++11", -- DEPRECATED "C++14", -- DEPRECATED @@ -1367,6 +1367,16 @@ api.deprecateValue("flags", "C11", 'Use `language "C11"` instead', function(value) end, function(value) end) + -- 13 April 2017 + + api.deprecateValue("flags", "WinMain", 'Use `entrypoint "WinMainCRTStartup"` instead', + function(value) + entrypoint "WinMainCRTStartup" + end, + function(value) + entrypoint "mainCRTStartup" + end) + ----------------------------------------------------------------------------- -- -- Install Premake's default set of command line arguments. @@ -1526,4 +1536,7 @@ filter { "system:macosx" } toolset "clang" + filter { "system:windows", "kind:WindowedApp or ConsoleApp" } + entrypoint "mainCRTStartup" + filter {} diff --git a/src/actions/vstudio/vs200x_vcproj.lua b/src/actions/vstudio/vs200x_vcproj.lua index a3dccd40..299b7adc 100644 --- a/src/actions/vstudio/vs200x_vcproj.lua +++ b/src/actions/vstudio/vs200x_vcproj.lua @@ -1121,11 +1121,8 @@ function m.entryPointSymbol(cfg, toolset) - if (cfg.kind == "ConsoleApp" or cfg.kind == "WindowedApp") and - not cfg.flags.WinMain and - not toolset - then - p.w('EntryPointSymbol="mainCRTStartup"') + if cfg.entrypoint then + p.w('EntryPointSymbol="%s"', cfg.entrypoint) end end diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index bf98ff61..9e33e54d 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -1310,14 +1310,6 @@ function m.entryPointSymbol(cfg) if cfg.entrypoint then m.element("EntryPointSymbol", nil, cfg.entrypoint) - else - if (cfg.kind == premake.CONSOLEAPP or cfg.kind == premake.WINDOWEDAPP) and - not cfg.flags.WinMain and - cfg.clr == p.OFF and - cfg.system ~= p.XBOX360 - then - m.element("EntryPointSymbol", nil, "mainCRTStartup") - end end end From b2bbf00512b82de87d3cd87a22ac05f80c10a299 Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Tue, 4 Apr 2017 19:17:00 +0300 Subject: [PATCH 18/59] Fix NuGet packages.config generation This was generated on a per-solution basis when one needed to be generated for each project. --- src/actions/vstudio/vs2005.lua | 14 ----- src/actions/vstudio/vs2010.lua | 6 ++ src/actions/vstudio/vs2010_nuget.lua | 39 ++----------- tests/_tests.lua | 3 +- .../cs2005/test_nuget_packages_config.lua | 57 +++++++++++++++++++ .../test_nuget_packages_config.lua | 21 +++++-- 6 files changed, 88 insertions(+), 52 deletions(-) create mode 100644 tests/actions/vstudio/cs2005/test_nuget_packages_config.lua rename tests/actions/vstudio/{sln2005 => vc2010}/test_nuget_packages_config.lua (64%) diff --git a/src/actions/vstudio/vs2005.lua b/src/actions/vstudio/vs2005.lua index 2a7ebc88..0be556e7 100644 --- a/src/actions/vstudio/vs2005.lua +++ b/src/actions/vstudio/vs2005.lua @@ -21,20 +21,6 @@ p.escaper(vs2005.esc) premake.generate(wks, ".sln", vstudio.sln2005.generate) - - if _ACTION >= "vs2010" then - -- Skip generation of empty NuGet packages.config files - if p.workspace.hasProject(wks, function(prj) return #prj.nuget > 0 end) then - premake.generate( - { - location = path.join(wks.location, "packages.config"), - workspace = wks - }, - nil, - vstudio.nuget2010.generatePackagesConfig - ) - end - end end diff --git a/src/actions/vstudio/vs2010.lua b/src/actions/vstudio/vs2010.lua index 4cd57f91..777eaf1e 100644 --- a/src/actions/vstudio/vs2010.lua +++ b/src/actions/vstudio/vs2010.lua @@ -72,6 +72,12 @@ premake.generate(prj, ".vcxproj.filters", vstudio.vc2010.generateFilters) end end + + -- Skip generation of empty packages.config files + local packages = p.capture(function() vstudio.nuget2010.generatePackagesConfig(prj) end) + if #packages > 0 then + p.generate(prj, "packages.config", function() p.outln(packages) end) + end end diff --git a/src/actions/vstudio/vs2010_nuget.lua b/src/actions/vstudio/vs2010_nuget.lua index de38fca0..1aa23797 100644 --- a/src/actions/vstudio/vs2010_nuget.lua +++ b/src/actions/vstudio/vs2010_nuget.lua @@ -29,21 +29,7 @@ return package:sub(package:find(":") + 1, -1) end - local function packageProject(wks, package) - for prj in p.workspace.eachproject(wks) do - for i = 1, #prj.nuget do - local projectPackage = prj.nuget[i] - - if projectPackage == package then - return prj - end - end - end - end - - function nuget2010.packageFramework(wks, package) - local prj = packageProject(wks, package) - + function nuget2010.packageFramework(prj) if p.project.isdotnet(prj) then local cfg = p.project.getfirstconfig(prj) local action = premake.action.current() @@ -59,28 +45,15 @@ -- Generates the packages.config file. -- - function nuget2010.generatePackagesConfig(obj) - local wks = obj.workspace - - local done = {} - local packages = {} - for prj in p.workspace.eachproject(wks) do - for i = 1, #prj.nuget do - local package = prj.nuget[i] - - if not done[package] then - done[package] = true - table.insert(packages, package) - end - end - end - + function nuget2010.generatePackagesConfig(prj) + if #prj.nuget > 0 then p.w('') p.push('') - for _, package in ipairs(packages) do - p.x('', nuget2010.packageId(package), nuget2010.packageVersion(package), nuget2010.packageFramework(wks, package)) + for _, package in ipairs(prj.nuget) do + p.x('', nuget2010.packageId(package), nuget2010.packageVersion(package), nuget2010.packageFramework(prj)) end p.pop('') end + end diff --git a/tests/_tests.lua b/tests/_tests.lua index 7773001f..00fa7ae0 100644 --- a/tests/_tests.lua +++ b/tests/_tests.lua @@ -70,6 +70,7 @@ return { "actions/vstudio/cs2005/test_debug_props.lua", "actions/vstudio/cs2005/test_files.lua", "actions/vstudio/cs2005/test_icon.lua", + "actions/vstudio/cs2005/test_nuget_packages_config.lua", "actions/vstudio/cs2005/test_output_props.lua", "actions/vstudio/cs2005/projectelement.lua", "actions/vstudio/cs2005/test_platform_groups.lua", @@ -85,7 +86,6 @@ return { "actions/vstudio/sln2005/test_projects.lua", "actions/vstudio/sln2005/test_platforms.lua", "actions/vstudio/sln2005/test_sections.lua", - "actions/vstudio/sln2005/test_nuget_packages_config.lua", -- Visual Studio 2002-2008 C/C++ projects "actions/vstudio/vc200x/test_assembly_refs.lua", @@ -128,6 +128,7 @@ return { "actions/vstudio/vc2010/test_link.lua", "actions/vstudio/vc2010/test_manifest.lua", "actions/vstudio/vc2010/test_nmake_props.lua", + "actions/vstudio/vc2010/test_nuget_packages_config.lua", "actions/vstudio/vc2010/test_output_props.lua", "actions/vstudio/vc2010/test_platform_toolset.lua", "actions/vstudio/vc2010/test_project_configs.lua", diff --git a/tests/actions/vstudio/cs2005/test_nuget_packages_config.lua b/tests/actions/vstudio/cs2005/test_nuget_packages_config.lua new file mode 100644 index 00000000..65a16961 --- /dev/null +++ b/tests/actions/vstudio/cs2005/test_nuget_packages_config.lua @@ -0,0 +1,57 @@ +-- +-- tests/actions/vstudio/cs2005/test_assembly_refs.lua +-- Validate generation of NuGet packages.config file for Visual Studio 2010 and newer. +-- Copyright (c) 2012-2015 Jason Perkins and the Premake project +-- + + local suite = test.declare("vstudio_cs2005_nuget_packages_config") + local cs2005 = premake.vstudio.cs2005 + local nuget2010 = premake.vstudio.nuget2010 + + +-- +-- Setup and teardown +-- + + local wks, prj + + function suite.setup() + premake.action.set("vs2010") + wks = test.createWorkspace() + language "C#" + end + + local function prepare(platform) + prj = test.getproject(wks, 1) + nuget2010.generatePackagesConfig(prj) + end + + +-- +-- Should not output anything if no packages have been set. +-- + + function suite.noOutputIfNoPackages() + prepare() + test.isemptycapture() + end + + + +-- +-- Writes the packages.config file properly. +-- + + function suite.structureIsCorrect() + dotnetframework "4.6" + nuget { "Newtonsoft.Json:10.0.2", "NUnit:3.6.1", "SSH.NET:2016.0.0" } + prepare() + test.capture [[ + + + + + + +]] + end diff --git a/tests/actions/vstudio/sln2005/test_nuget_packages_config.lua b/tests/actions/vstudio/vc2010/test_nuget_packages_config.lua similarity index 64% rename from tests/actions/vstudio/sln2005/test_nuget_packages_config.lua rename to tests/actions/vstudio/vc2010/test_nuget_packages_config.lua index f383efa9..44c4b89c 100644 --- a/tests/actions/vstudio/sln2005/test_nuget_packages_config.lua +++ b/tests/actions/vstudio/vc2010/test_nuget_packages_config.lua @@ -1,11 +1,13 @@ -- --- tests/actions/vstudio/sln2005/test_nuget_packages_config.lua +-- tests/actions/vstudio/vc2010/test_nuget_packages_config.lua -- Validate generation of NuGet packages.config file for Visual Studio 2010 and newer. --- Copyright (c) 2016 Jason Perkins and the Premake project +-- Copyright (c) 2017 Jason Perkins and the Premake project -- - local suite = test.declare("vstudio_sln2005_nuget_packages_config") + local suite = test.declare("vs2010_nuget_packages_config") + local vc2010 = premake.vstudio.vc2010 local nuget2010 = premake.vstudio.nuget2010 + local project = premake.project -- @@ -21,10 +23,21 @@ local function prepare() local prj = premake.solution.getproject(wks, 1) - nuget2010.generatePackagesConfig({ workspace = wks }) + nuget2010.generatePackagesConfig(prj) end +-- +-- Should not output anything if no packages have been set. +-- + + function suite.noOutputIfNoPackages() + prepare() + test.isemptycapture() + end + + + -- -- Writes the packages.config file properly. -- From 77463534c902414a9ceca3f980bccfdd1d6eda2a Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Tue, 4 Apr 2017 19:17:08 +0300 Subject: [PATCH 19/59] Fix NuGet packages.config files missing from projects --- src/base/oven.lua | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/base/oven.lua b/src/base/oven.lua index a781ac91..30dd423d 100644 --- a/src/base/oven.lua +++ b/src/base/oven.lua @@ -634,7 +634,7 @@ -- I need to look at them all. for cfg in p.project.eachconfig(prj) do - table.foreachi(cfg.files, function(fname) + local function addFile(fname) -- If this is the first time I've seen this file, start a new -- file configuration for it. Track both by key for quick lookups @@ -648,7 +648,17 @@ p.fileconfig.addconfig(files[fname], cfg) - end) + end + + table.foreachi(cfg.files, addFile) + + -- If this project uses NuGet, we need to add the generated + -- packages.config file to the project. Is there a better place to + -- do this? + + if #prj.nuget > 0 then + addFile("packages.config") + end end -- Alpha sort the indices, so I will get consistent results in From 39720da733c192f72efc3cff1d27c2918b0cac12 Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Thu, 6 Apr 2017 17:55:26 +0300 Subject: [PATCH 20/59] Raise error on packages.config conflict --- src/base/validation.lua | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/base/validation.lua b/src/base/validation.lua index 8ace733b..1744fc77 100644 --- a/src/base/validation.lua +++ b/src/base/validation.lua @@ -39,6 +39,7 @@ return { m.workspaceHasConfigs, m.uniqueProjectIds, + m.uniqueProjectLocationsWithNuGet, } end @@ -233,6 +234,29 @@ end + function m.uniqueProjectLocationsWithNuGet(wks) + local locations = {} + for prj in p.workspace.eachproject(wks) do + local function fail() + p.error("projects '%s' and '%s' cannot have the same location when using NuGet with different packages (packages.config conflict)", locations[prj.location].name, prj.name) + end + + if locations[prj.location] and #locations[prj.location].nuget > 0 and #prj.nuget > 0 then + if #locations[prj.location].nuget ~= #prj.nuget then + fail() + end + + for i, package in ipairs(locations[prj.location].nuget) do + if prj.nuget[i] ~= package then + fail() + end + end + end + locations[prj.location] = prj + end + end + + function m.workspaceHasConfigs(wks) if not wks.configurations or #wks.configurations == 0 then p.error("workspace '%s' does not contain any configurations", wks.name) From cbcb942e57278d90d297791fdcb7628fa7aeb364 Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Thu, 6 Apr 2017 18:47:13 +0300 Subject: [PATCH 21/59] Validate NuGet package names with the NuGet API --- src/actions/vstudio/vs2010_nuget.lua | 30 ++++++++++++++++++++++++++++ src/base/validation.lua | 6 ++++++ 2 files changed, 36 insertions(+) diff --git a/src/actions/vstudio/vs2010_nuget.lua b/src/actions/vstudio/vs2010_nuget.lua index 1aa23797..c61d38f6 100644 --- a/src/actions/vstudio/vs2010_nuget.lua +++ b/src/actions/vstudio/vs2010_nuget.lua @@ -41,6 +41,36 @@ end + local validatedPackages = {} + + function nuget2010.validatePackages(prj) + if #prj.nuget == 0 then + return + end + + for _, package in ipairs(prj.nuget) do + local id = nuget2010.packageId(package) + local version = nuget2010.packageVersion(package) + + if not validatedPackages[id] then + printf("Examining NuGet package '%s'...", id) + io.flush() + + local response, err, code = http.get(string.format("https://api.nuget.org/v3/registration1/%s/index.json", id:lower())) + + if err ~= "OK" then + if code == 404 then + p.error("NuGet package '%s' for project '%s' couldn't be found in the repository", id, prj.name) + else + p.error("NuGet API error (%d)\n%s", code, err) + end + end + end + validatedPackages[id] = package + end + end + + -- -- Generates the packages.config file. -- diff --git a/src/base/validation.lua b/src/base/validation.lua index 1744fc77..4ef19290 100644 --- a/src/base/validation.lua +++ b/src/base/validation.lua @@ -61,6 +61,7 @@ m.actionSupportsKind, m.projectRulesExist, m.projectValuesInScope, + m.projectNuGetPackages, } end @@ -223,6 +224,11 @@ end + function m.projectNuGetPackages(prj) + p.vstudio.nuget2010.validatePackages(prj) + end + + function m.uniqueProjectIds(wks) local uuids = {} for prj in p.workspace.eachproject(wks) do From bb992e65764adb5b40025e9e9c9ad3eb289f8f3c Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Thu, 6 Apr 2017 20:28:52 +0300 Subject: [PATCH 22/59] Validate NuGet package versions with the NuGet API --- src/actions/vstudio/vs2005_csproj.lua | 6 +- src/actions/vstudio/vs2010_nuget.lua | 93 ++++++++++++++++++++++++-- src/actions/vstudio/vs2010_vcxproj.lua | 3 +- 3 files changed, 92 insertions(+), 10 deletions(-) diff --git a/src/actions/vstudio/vs2005_csproj.lua b/src/actions/vstudio/vs2005_csproj.lua index f4893194..f9680873 100644 --- a/src/actions/vstudio/vs2005_csproj.lua +++ b/src/actions/vstudio/vs2005_csproj.lua @@ -377,13 +377,15 @@ -- HintPaths (if the condition is met that is). for _, frameworkVersion in ipairs(cs2005.identifyFrameworkVersions(prj)) do + local packageAPIInfo = vstudio.nuget2010.packageAPIInfo(package) local assembly = vstudio.path( prj, p.filename( prj.solution, string.format( - "packages\\%s\\lib\\%s\\%s.dll", - vstudio.nuget2010.packageName(package), + "packages\\%s.%s\\lib\\%s\\%s.dll", + vstudio.nuget2010.packageId(package), + packageAPIInfo.verbatimVersion or packageAPIInfo.version, cs2005.formatNuGetFrameworkVersion(frameworkVersion), vstudio.nuget2010.packageId(package) ) diff --git a/src/actions/vstudio/vs2010_nuget.lua b/src/actions/vstudio/vs2010_nuget.lua index c61d38f6..e4285f30 100644 --- a/src/actions/vstudio/vs2010_nuget.lua +++ b/src/actions/vstudio/vs2010_nuget.lua @@ -11,16 +11,13 @@ local nuget2010 = p.vstudio.nuget2010 local cs2005 = p.vstudio.cs2005 + local packageAPIInfos = {} -- -- These functions take the package string as an argument and give you -- information about it. -- - function nuget2010.packageName(package) - return package:gsub(":", ".") - end - function nuget2010.packageId(package) return package:sub(0, package:find(":") - 1) end @@ -40,8 +37,10 @@ end end + function nuget2010.packageAPIInfo(package) + return packageAPIInfos[package] + end - local validatedPackages = {} function nuget2010.validatePackages(prj) if #prj.nuget == 0 then @@ -52,7 +51,9 @@ local id = nuget2010.packageId(package) local version = nuget2010.packageVersion(package) - if not validatedPackages[id] then + if not packageAPIInfos[package] then + local packageAPIInfo = {} + printf("Examining NuGet package '%s'...", id) io.flush() @@ -65,8 +66,86 @@ p.error("NuGet API error (%d)\n%s", code, err) end end + + response, err = json.decode(response) + + if not response then + p.error("Failed to decode NuGet API response (%s)", err) + end + + if not response.items or #response.items == 0 then + p.error("Failed to understand NuGet API response (package '%s' contains no root-level items)", id) + end + + if not response.items[1].items or #response.items[1].items == 0 then + p.error("Failed to understand NuGet API response (root-level item for package '%s' contains no subitems)", id) + end + + local subitems = response.items[1].items + + local versions = {} + + for _, item in ipairs(subitems) do + if not item.catalogEntry then + p.error("Failed to understand NuGet API response (subitem of package '%s' has no catalogEntry)", id) + end + + if not item.catalogEntry.version then + p.error("Failed to understand NuGet API response (subitem of package '%s' has no catalogEntry.version)", id) + end + + if not item.catalogEntry["@id"] then + p.error("Failed to understand NuGet API response (subitem of package '%s' has no catalogEntry['@id'])", id) + end + + -- Check this URL just in case. We don't want to be making + -- requests to anywhere else. + + if item.catalogEntry["@id"]:find("https://api.nuget.org/") ~= 1 then + p.error("Failed to understand NuGet API response (catalogEntry['@id'] was not a NuGet API URL)", id) + end + + table.insert(versions, item.catalogEntry.version) + end + + if not table.contains(versions, version) then + local options = table.translate(versions, function(value) return "'" .. value .. "'" end) + options = table.concat(options, ", ") + + p.error("'%s' is not a valid version for NuGet package '%s' (options are: %s)", version, id, options) + end + + for _, item in ipairs(subitems) do + if item.catalogEntry.version == version then + local response, err, code = http.get(item.catalogEntry["@id"]) + + if err ~= "OK" then + if code == 404 then + p.error("NuGet package '%s' version '%s' couldn't be found in the repository even though the API reported that it exists", id, prj.name) + else + p.error("NuGet API error (%d)\n%s", code, err) + end + end + + response, err = json.decode(response) + + if not response then + p.error("Failed to decode NuGet API response (%s)", err) + end + + if not response.verbatimVersion and not response.version then + p.error("Failed to understand NuGet API response (package '%s' version '%s' has no verbatimVersion or version)", id, version) + end + + packageAPIInfo.verbatimVersion = response.verbatimVersion + packageAPIInfo.version = response.version + + break + end + end + + packageAPIInfos[package] = packageAPIInfo end - validatedPackages[id] = package end end diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index bf98ff61..f6219d0e 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -1552,7 +1552,8 @@ end local function nuGetTargetsFile(prj, package) - return p.vstudio.path(prj, p.filename(prj.solution, string.format("packages\\%s\\build\\native\\%s.targets", vstudio.nuget2010.packageName(package), vstudio.nuget2010.packageId(package)))) + local packageAPIInfo = vstudio.nuget2010.packageAPIInfo(package) + return p.vstudio.path(prj, p.filename(prj.solution, string.format("packages\\%s.%s\\build\\native\\%s.targets", vstudio.nuget2010.packageId(package), packageAPIInfo.verbatimVersion or packageAPIInfo.version, vstudio.nuget2010.packageId(package)))) end function m.importNuGetTargets(prj) From c57477229cf4895bfab336cc3cb21f5050311e3a Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Fri, 7 Apr 2017 17:07:17 +0300 Subject: [PATCH 23/59] Fix NuGet assembly references in C# projects For C# projects, we need to get the assembly paths from the NuGet API, instead of assuming that the package only contains one assembly with the same name as the package. --- src/actions/vstudio/_vstudio.lua | 17 ---- src/actions/vstudio/vs2005_csproj.lua | 128 ++++++++++++++++---------- src/actions/vstudio/vs2010_nuget.lua | 25 +++++ 3 files changed, 103 insertions(+), 67 deletions(-) diff --git a/src/actions/vstudio/_vstudio.lua b/src/actions/vstudio/_vstudio.lua index 001ee8de..e0b8e0c0 100644 --- a/src/actions/vstudio/_vstudio.lua +++ b/src/actions/vstudio/_vstudio.lua @@ -12,23 +12,6 @@ local config = p.config --- --- All valid .NET Framework versions, from oldest to newest. --- - - vstudio.frameworkVersions = - { - "1.0", - "1.1", - "2.0", - "3.0", - "3.5", - "4.0", - "4.5", - "4.6", - } - - -- -- Mapping tables from Premake systems and architectures to Visual Studio -- identifiers. Broken out as tables so new values can be pushed in by diff --git a/src/actions/vstudio/vs2005_csproj.lua b/src/actions/vstudio/vs2005_csproj.lua index f9680873..afaaceee 100644 --- a/src/actions/vstudio/vs2005_csproj.lua +++ b/src/actions/vstudio/vs2005_csproj.lua @@ -368,35 +368,89 @@ function cs2005.nuGetReferences(prj) if _ACTION >= "vs2010" then - for i = 1, #prj.nuget do - local package = prj.nuget[i] - _x(2, '', vstudio.nuget2010.packageId(package)) + for _, package in ipairs(prj.nuget) do + local id = vstudio.nuget2010.packageId(package) + local packageAPIInfo = vstudio.nuget2010.packageAPIInfo(package) - -- We need to write HintPaths for all supported framework - -- versions. The last HintPath will override any previous - -- HintPaths (if the condition is met that is). + local cfg = p.project.getfirstconfig(prj) + local action = premake.action.current() + local targetFramework = cfg.dotnetframework or action.vstudio.targetFramework - for _, frameworkVersion in ipairs(cs2005.identifyFrameworkVersions(prj)) do - local packageAPIInfo = vstudio.nuget2010.packageAPIInfo(package) - local assembly = vstudio.path( - prj, - p.filename( - prj.solution, - string.format( - "packages\\%s.%s\\lib\\%s\\%s.dll", - vstudio.nuget2010.packageId(package), - packageAPIInfo.verbatimVersion or packageAPIInfo.version, - cs2005.formatNuGetFrameworkVersion(frameworkVersion), - vstudio.nuget2010.packageId(package) - ) - ) - ) + -- This is a bit janky. To compare versions, we extract all + -- numbers from the given string and right-pad the result with + -- zeros. Then we can just do a lexicographical compare on the + -- resulting strings. + -- + -- This is so that we can compare version strings such as + -- "4.6" and "net451" with each other. - _x(3, '%s', assembly, assembly) + local function makeVersionComparable(a) + local numbers = "" + + for number in a:gmatch("%d") do + numbers = numbers .. number + end + + return string.format("%-10d", numbers):gsub(" ", "0") end - _p(3, 'True') - _p(2, '') + local targetVersion = makeVersionComparable(targetFramework) + + -- Figure out what folder contains the files for the nearest + -- supported .NET Framework version. + + local files = {} + + local bestVersion, bestFolder + + for _, file in ipairs(packageAPIInfo.packageEntries) do + -- If this exporter ever supports frameworks such as + -- "netstandard1.3", "sl4", "sl5", "uap10", "wp8" or + -- "wp71", this code will need changing to match the right + -- folders. + + local folder = file:match("^lib\\net(%d+)\\") + + if folder and path.hasextension(file, ".dll") then + files[folder] = files[folder] or {} + table.insert(files[folder], file) + + local version = makeVersionComparable(file:match("lib\\net(%d+)\\")) + + if version <= targetVersion and (not bestVersion or version > bestVersion) then + bestVersion = version + bestFolder = folder + end + end + end + + if not bestVersion then + p.error("NuGet package '%s' is not compatible with project '%s' .NET Framework version '%s'", id, prj.name, targetFramework) + end + + -- Now, add references for all DLLs in that folder. + + for _, file in ipairs(files[bestFolder]) do + -- There's some stuff missing from this include that we + -- can't get from the API and would need to download and + -- extract the package to figure out. It looks like we can + -- just omit it though. + -- + -- So, for example, instead of: + -- + -- + -- + -- We're just outputting: + -- + -- + + _x(2, '', path.getbasename(file)) + _x(3, '%s', vstudio.path(prj, p.filename(prj.solution, string.format("packages\\%s.%s\\%s", id, packageAPIInfo.verbatimVersion or packageAPIInfo.version, file)))) + _p(3, 'True') + _p(2, '') + end end end end @@ -487,32 +541,6 @@ end --- --- Build and return a list of all .NET Framework versions up to and including --- the project's framework version. --- - - function cs2005.identifyFrameworkVersions(prj) - local frameworks = {} - - local cfg = p.project.getfirstconfig(prj) - local action = premake.action.current() - local targetFramework = cfg.dotnetframework or action.vstudio.targetFramework - - for _, frameworkVersion in ipairs(vstudio.frameworkVersions) do - if frameworkVersion == targetFramework then - break - end - - table.insert(frameworks, frameworkVersion) - end - - table.insert(frameworks, targetFramework) - - return frameworks - end - - -- -- When given a .NET Framework version, returns it formatted for NuGet. -- diff --git a/src/actions/vstudio/vs2010_nuget.lua b/src/actions/vstudio/vs2010_nuget.lua index e4285f30..c3e30c05 100644 --- a/src/actions/vstudio/vs2010_nuget.lua +++ b/src/actions/vstudio/vs2010_nuget.lua @@ -140,6 +140,31 @@ packageAPIInfo.verbatimVersion = response.verbatimVersion packageAPIInfo.version = response.version + -- C++ packages don't have this, but C# packages have a + -- packageEntries field that lists all the files in the + -- package. We need to look at this to figure out what + -- DLLs to reference in the project file. + + if prj.language == "C#" and not response.packageEntries then + p.error("NuGet package '%s' has no file listing (are you sure referenced a .NET package and not a native package?)", id) + end + + if prj.language == "C#" then + packageAPIInfo.packageEntries = {} + + for _, item in ipairs(response.packageEntries) do + if not item.fullName then + p.error("Failed to understand NuGet API response (package '%s' version '%s' packageEntry has no fullName)", id, version) + end + + table.insert(packageAPIInfo.packageEntries, path.translate(item.fullName)) + end + + if #packageAPIInfo.packageEntries == 0 then + p.error("NuGet package '%s' file listing is empty", id) + end + end + break end end From bd3c542d6397ec854f09114c703baafcacc3ed29 Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Fri, 7 Apr 2017 17:25:35 +0300 Subject: [PATCH 24/59] Fetch NuGet API data on demand, not all at once --- src/actions/vstudio/vs2005_csproj.lua | 2 +- src/actions/vstudio/vs2010_nuget.lua | 15 +++------------ src/actions/vstudio/vs2010_vcxproj.lua | 2 +- src/base/validation.lua | 6 ------ 4 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/actions/vstudio/vs2005_csproj.lua b/src/actions/vstudio/vs2005_csproj.lua index afaaceee..20bd9ce6 100644 --- a/src/actions/vstudio/vs2005_csproj.lua +++ b/src/actions/vstudio/vs2005_csproj.lua @@ -370,7 +370,7 @@ if _ACTION >= "vs2010" then for _, package in ipairs(prj.nuget) do local id = vstudio.nuget2010.packageId(package) - local packageAPIInfo = vstudio.nuget2010.packageAPIInfo(package) + local packageAPIInfo = vstudio.nuget2010.packageAPIInfo(prj, package) local cfg = p.project.getfirstconfig(prj) local action = premake.action.current() diff --git a/src/actions/vstudio/vs2010_nuget.lua b/src/actions/vstudio/vs2010_nuget.lua index c3e30c05..6ce7c17a 100644 --- a/src/actions/vstudio/vs2010_nuget.lua +++ b/src/actions/vstudio/vs2010_nuget.lua @@ -37,17 +37,7 @@ end end - function nuget2010.packageAPIInfo(package) - return packageAPIInfos[package] - end - - - function nuget2010.validatePackages(prj) - if #prj.nuget == 0 then - return - end - - for _, package in ipairs(prj.nuget) do + function nuget2010.packageAPIInfo(prj, package) local id = nuget2010.packageId(package) local version = nuget2010.packageVersion(package) @@ -171,7 +161,8 @@ packageAPIInfos[package] = packageAPIInfo end - end + + return packageAPIInfos[package] end diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index f6219d0e..4739fde0 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -1552,7 +1552,7 @@ end local function nuGetTargetsFile(prj, package) - local packageAPIInfo = vstudio.nuget2010.packageAPIInfo(package) + local packageAPIInfo = vstudio.nuget2010.packageAPIInfo(prj, package) return p.vstudio.path(prj, p.filename(prj.solution, string.format("packages\\%s.%s\\build\\native\\%s.targets", vstudio.nuget2010.packageId(package), packageAPIInfo.verbatimVersion or packageAPIInfo.version, vstudio.nuget2010.packageId(package)))) end diff --git a/src/base/validation.lua b/src/base/validation.lua index 4ef19290..1744fc77 100644 --- a/src/base/validation.lua +++ b/src/base/validation.lua @@ -61,7 +61,6 @@ m.actionSupportsKind, m.projectRulesExist, m.projectValuesInScope, - m.projectNuGetPackages, } end @@ -224,11 +223,6 @@ end - function m.projectNuGetPackages(prj) - p.vstudio.nuget2010.validatePackages(prj) - end - - function m.uniqueProjectIds(wks) local uuids = {} for prj in p.workspace.eachproject(wks) do From 3bdf746fcc76e54ebb0739031e5e3f60ab1baf29 Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Fri, 7 Apr 2017 17:39:11 +0300 Subject: [PATCH 25/59] Fix C# NuGet tests --- src/actions/vstudio/vs2010_nuget.lua | 2 +- .../vstudio/cs2005/test_assembly_refs.lua | 27 +++++-------------- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/src/actions/vstudio/vs2010_nuget.lua b/src/actions/vstudio/vs2010_nuget.lua index 6ce7c17a..d8818b14 100644 --- a/src/actions/vstudio/vs2010_nuget.lua +++ b/src/actions/vstudio/vs2010_nuget.lua @@ -136,7 +136,7 @@ -- DLLs to reference in the project file. if prj.language == "C#" and not response.packageEntries then - p.error("NuGet package '%s' has no file listing (are you sure referenced a .NET package and not a native package?)", id) + p.error("NuGet package '%s' has no file listing. This package might be too old to be using this API or it's not a .NET Framework package at all.", id) end if prj.language == "C#" then diff --git a/tests/actions/vstudio/cs2005/test_assembly_refs.lua b/tests/actions/vstudio/cs2005/test_assembly_refs.lua index e8ebdbce..474495ab 100644 --- a/tests/actions/vstudio/cs2005/test_assembly_refs.lua +++ b/tests/actions/vstudio/cs2005/test_assembly_refs.lua @@ -147,43 +147,28 @@ -- NuGet packages should get references. -- - function suite.nuGetPackages() + function suite.nuGetPackages_net45() dotnetframework "4.5" - nuget { "Newtonsoft.Json:7.0.1" } + nuget { "Newtonsoft.Json:10.0.2" } prepare() test.capture [[ - packages\Newtonsoft.Json.7.0.1\lib\net10\Newtonsoft.Json.dll - packages\Newtonsoft.Json.7.0.1\lib\net11\Newtonsoft.Json.dll - packages\Newtonsoft.Json.7.0.1\lib\net20\Newtonsoft.Json.dll - packages\Newtonsoft.Json.7.0.1\lib\net30\Newtonsoft.Json.dll - packages\Newtonsoft.Json.7.0.1\lib\net35\Newtonsoft.Json.dll - packages\Newtonsoft.Json.7.0.1\lib\net40\Newtonsoft.Json.dll - packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll True ]] end - --- --- NuGet packages shouldn't get HintPaths for .NET Framework --- versions that the project doesn't support. --- - - function suite.nuGetPackages_olderNET() + function suite.nuGetPackages_net30() dotnetframework "3.0" - nuget { "Newtonsoft.Json:7.0.1" } + nuget { "Newtonsoft.Json:10.0.2" } prepare() test.capture [[ - packages\Newtonsoft.Json.7.0.1\lib\net10\Newtonsoft.Json.dll - packages\Newtonsoft.Json.7.0.1\lib\net11\Newtonsoft.Json.dll - packages\Newtonsoft.Json.7.0.1\lib\net20\Newtonsoft.Json.dll - packages\Newtonsoft.Json.7.0.1\lib\net30\Newtonsoft.Json.dll + packages\Newtonsoft.Json.10.0.2\lib\net20\Newtonsoft.Json.dll True From df6c1f4aab2dd8e17b936abe8530b3f40df77294 Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Fri, 7 Apr 2017 17:43:03 +0300 Subject: [PATCH 26/59] Add test for multiple assemblies in C# NuGet packages --- .../vstudio/cs2005/test_assembly_refs.lua | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/actions/vstudio/cs2005/test_assembly_refs.lua b/tests/actions/vstudio/cs2005/test_assembly_refs.lua index 474495ab..5602926b 100644 --- a/tests/actions/vstudio/cs2005/test_assembly_refs.lua +++ b/tests/actions/vstudio/cs2005/test_assembly_refs.lua @@ -174,3 +174,26 @@ ]] end + +-- +-- If there are multiple assemblies in the NuGet package, they all should be +-- referenced. +-- + + function suite.nuGetPackages_multipleAssemblies() + dotnetframework "2.0" + nuget { "NUnit:3.6.1" } + prepare() + test.capture [[ + + + packages\NUnit.3.6.1\lib\net20\nunit.framework.dll + True + + + packages\NUnit.3.6.1\lib\net20\NUnit.System.Linq.dll + True + + + ]] + end From 34eb9c691a55a90d3100ef4a70b211b26367317c Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Fri, 7 Apr 2017 17:53:39 +0300 Subject: [PATCH 27/59] Fix certain NuGet API error messages --- src/actions/vstudio/vs2010_nuget.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/actions/vstudio/vs2010_nuget.lua b/src/actions/vstudio/vs2010_nuget.lua index d8818b14..1947e0ae 100644 --- a/src/actions/vstudio/vs2010_nuget.lua +++ b/src/actions/vstudio/vs2010_nuget.lua @@ -111,7 +111,7 @@ if err ~= "OK" then if code == 404 then - p.error("NuGet package '%s' version '%s' couldn't be found in the repository even though the API reported that it exists", id, prj.name) + p.error("NuGet package '%s' version '%s' couldn't be found in the repository even though the API reported that it exists", id, version) else p.error("NuGet API error (%d)\n%s", code, err) end @@ -136,7 +136,7 @@ -- DLLs to reference in the project file. if prj.language == "C#" and not response.packageEntries then - p.error("NuGet package '%s' has no file listing. This package might be too old to be using this API or it's not a .NET Framework package at all.", id) + p.error("NuGet package '%s' version '%s' has no file listing. This package might be too old to be using this API or it might be a C++ package instead of a .NET Framework package.", id, response.version) end if prj.language == "C#" then From 52b21eefdb563e3b1d9c423bac9f63403404f3ab Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Sat, 8 Apr 2017 23:34:41 +0300 Subject: [PATCH 28/59] Raise an error if trying to use NuGet without Curl --- src/base/validation.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/base/validation.lua b/src/base/validation.lua index 1744fc77..fa958548 100644 --- a/src/base/validation.lua +++ b/src/base/validation.lua @@ -61,6 +61,7 @@ m.actionSupportsKind, m.projectRulesExist, m.projectValuesInScope, + m.NuGetHasHTTP, } end @@ -223,6 +224,13 @@ end + function m.NuGetHasHTTP(prj) + if not http and #prj.nuget > 0 then + p.error("Premake was compiled with --no-curl, but Curl is required for NuGet support (project '%s' is referencing NuGet packages)", prj.name) + end + end + + function m.uniqueProjectIds(wks) local uuids = {} for prj in p.workspace.eachproject(wks) do From 8286a7b9b63273fe2b06bdd5ee6ab1e97c8d5f8c Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Sun, 9 Apr 2017 13:55:14 +0300 Subject: [PATCH 29/59] Add nugetsource API for custom package sources Non-gallery sources (such as NuGet.Server) are currently unsupported due to API limitations. --- src/_premake_init.lua | 8 ++ src/actions/vstudio/vs2010.lua | 6 ++ src/actions/vstudio/vs2010_nuget.lua | 99 +++++++++++++++++-- tests/_tests.lua | 1 + .../vstudio/cs2005/test_nuget_config.lua | 82 +++++++++++++++ 5 files changed, 188 insertions(+), 8 deletions(-) create mode 100644 tests/actions/vstudio/cs2005/test_nuget_config.lua diff --git a/src/_premake_init.lua b/src/_premake_init.lua index c1a57449..4f9a793d 100644 --- a/src/_premake_init.lua +++ b/src/_premake_init.lua @@ -790,6 +790,13 @@ tokens = true, } + api.register { + name = "nugetsource", + scope = "project", + kind = "string", + tokens = true, + } + api.register { name = "objdir", scope = "config", @@ -1478,6 +1485,7 @@ exceptionhandling "Default" rtti "Default" symbols "Default" + nugetsource "https://api.nuget.org/v3/index.json" -- Setting a default language makes some validation easier later diff --git a/src/actions/vstudio/vs2010.lua b/src/actions/vstudio/vs2010.lua index 777eaf1e..8d226fb4 100644 --- a/src/actions/vstudio/vs2010.lua +++ b/src/actions/vstudio/vs2010.lua @@ -78,6 +78,12 @@ if #packages > 0 then p.generate(prj, "packages.config", function() p.outln(packages) end) end + + -- Skip generation of empty NuGet.Config files + local config = p.capture(function() vstudio.nuget2010.generateNuGetConfig(prj) end) + if #config > 0 then + p.generate(prj, "NuGet.Config", function() p.outln(config) end) + end end diff --git a/src/actions/vstudio/vs2010_nuget.lua b/src/actions/vstudio/vs2010_nuget.lua index 1947e0ae..465d5596 100644 --- a/src/actions/vstudio/vs2010_nuget.lua +++ b/src/actions/vstudio/vs2010_nuget.lua @@ -12,6 +12,7 @@ local cs2005 = p.vstudio.cs2005 local packageAPIInfos = {} + local packageSourceInfos = {} -- -- These functions take the package string as an argument and give you @@ -41,13 +42,73 @@ local id = nuget2010.packageId(package) local version = nuget2010.packageVersion(package) + if not packageSourceInfos[prj.nugetsource] then + local packageSourceInfo = {} + + printf("Examining NuGet package source '%s'...", prj.nugetsource) + io.flush() + + local response, err, code = http.get(prj.nugetsource) + + if err ~= "OK" then + p.error("NuGet API error (%d)\n%s", code, err) + end + + response, err = json.decode(response) + + if not response then + p.error("Failed to decode NuGet API response (%s)", err) + end + + if not response.resources then + p.error("Failed to understand NuGet API response (no resources in response)", id) + end + + local packageDisplayMetadataUriTemplate, catalog + + for _, resource in ipairs(response.resources) do + if not resource["@id"] then + p.error("Failed to understand NuGet API response (no resource['@id'])") + end + + if not resource["@type"] then + p.error("Failed to understand NuGet API response (no resource['@type'])") + end + + if resource["@type"]:find("PackageDisplayMetadataUriTemplate") == 1 then + packageDisplayMetadataUriTemplate = resource + end + + if resource["@type"]:find("Catalog") == 1 then + catalog = resource + end + end + + if not packageDisplayMetadataUriTemplate then + p.error("Failed to understand NuGet API response (no PackageDisplayMetadataUriTemplate resource)") + end + + if not catalog then + if prj.nugetsource == "https://api.nuget.org/v3/index.json" then + p.error("Failed to understand NuGet API response (no Catalog resource)") + else + p.error("Package source is not a NuGet gallery - non-gallery sources are currently unsupported", prj.nugetsource, prj.name) + end + end + + packageSourceInfo.packageDisplayMetadataUriTemplate = packageDisplayMetadataUriTemplate + packageSourceInfo.catalog = catalog + + packageSourceInfos[prj.nugetsource] = packageSourceInfo + end + if not packageAPIInfos[package] then local packageAPIInfo = {} printf("Examining NuGet package '%s'...", id) io.flush() - local response, err, code = http.get(string.format("https://api.nuget.org/v3/registration1/%s/index.json", id:lower())) + local response, err, code = http.get(packageSourceInfos[prj.nugetsource].packageDisplayMetadataUriTemplate["@id"]:gsub("{id%-lower}", id:lower())) if err ~= "OK" then if code == 404 then @@ -88,13 +149,6 @@ p.error("Failed to understand NuGet API response (subitem of package '%s' has no catalogEntry['@id'])", id) end - -- Check this URL just in case. We don't want to be making - -- requests to anywhere else. - - if item.catalogEntry["@id"]:find("https://api.nuget.org/") ~= 1 then - p.error("Failed to understand NuGet API response (catalogEntry['@id'] was not a NuGet API URL)", id) - end - table.insert(versions, item.catalogEntry.version) end @@ -182,3 +236,32 @@ p.pop('') end end + + +-- +-- Generates the NuGet.Config file. +-- + + function nuget2010.generateNuGetConfig(prj) + if #prj.nuget == 0 then + return + end + + if prj.nugetsource == "https://api.nuget.org/v3/index.json" then + return + end + + p.w('') + p.push('') + p.push('') + + -- By specifying "", we ensure that only the source that we + -- define below is used. Otherwise it would just get added to the list + -- of package sources. + + p.x('') + + p.x('', prj.nugetsource, prj.nugetsource) + p.pop('') + p.pop('') + end diff --git a/tests/_tests.lua b/tests/_tests.lua index 00fa7ae0..eb9b373b 100644 --- a/tests/_tests.lua +++ b/tests/_tests.lua @@ -70,6 +70,7 @@ return { "actions/vstudio/cs2005/test_debug_props.lua", "actions/vstudio/cs2005/test_files.lua", "actions/vstudio/cs2005/test_icon.lua", + "actions/vstudio/cs2005/test_nuget_config.lua", "actions/vstudio/cs2005/test_nuget_packages_config.lua", "actions/vstudio/cs2005/test_output_props.lua", "actions/vstudio/cs2005/projectelement.lua", diff --git a/tests/actions/vstudio/cs2005/test_nuget_config.lua b/tests/actions/vstudio/cs2005/test_nuget_config.lua new file mode 100644 index 00000000..88a48099 --- /dev/null +++ b/tests/actions/vstudio/cs2005/test_nuget_config.lua @@ -0,0 +1,82 @@ +-- +-- tests/actions/vstudio/cs2005/test_nuget_config.lua +-- Validate generation of NuGet.Config files for Visual Studio 2010 and newer +-- Copyright (c) 2017 Jason Perkins and the Premake project +-- + + local suite = test.declare("vstudio_cs2005_nuget_config") + local cs2005 = premake.vstudio.cs2005 + local nuget2010 = premake.vstudio.nuget2010 + + +-- +-- Setup and teardown +-- + + local wks, prj + + function suite.setup() + premake.action.set("vs2010") + wks = test.createWorkspace() + language "C#" + end + + local function prepare(platform) + prj = test.getproject(wks, 1) + nuget2010.generateNuGetConfig(prj) + end + + +-- +-- Shouldn't output a file if no packages or sources have been set. +-- + + function suite.noOutputIfNoPackages() + prepare() + test.isemptycapture() + end + + +-- +-- Shouldn't output a file if no package sources have been set. +-- + + function suite.noOutputIfNoPackageSources() + dotnetframework "4.6" + nuget "NUnit:3.6.1" + prepare() + test.isemptycapture() + end + + +-- +-- Shouldn't output a file if no packages have been set. +-- + + function suite.noOutputIfNoPackagesButSource() + dotnetframework "4.6" + nugetsource "https://www.myget.org/F/premake-nuget-test/api/v3/index.json" + prepare() + test.isemptycapture() + end + + +-- +-- Writes the NuGet.Config file properly. +-- + + function suite.structureIsCorrect() + dotnetframework "4.6" + nuget "NUnit:3.6.1" + nugetsource "https://www.myget.org/F/premake-nuget-test/api/v3/index.json" + prepare() + test.capture [[ + + + + + + + +]] + end From 87f527c1dfc3b215e1ebee027fa184d2e02302bd Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Tue, 11 Apr 2017 14:08:40 +0300 Subject: [PATCH 30/59] Validate NuGet package strings --- src/base/validation.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/base/validation.lua b/src/base/validation.lua index fa958548..335cc26c 100644 --- a/src/base/validation.lua +++ b/src/base/validation.lua @@ -62,6 +62,7 @@ m.projectRulesExist, m.projectValuesInScope, m.NuGetHasHTTP, + m.NuGetPackageStrings, } end @@ -231,6 +232,17 @@ end + function m.NuGetPackageStrings(prj) + for _, package in ipairs(prj.nuget) do + local components = package:explode(":") + + if #components ~= 2 or #components[1] == 0 or #components[2] == 0 then + p.error("NuGet package '%s' in project '%s' is invalid - please give packages in the format 'id:version', e.g. 'NUnit:3.6.1'", package, prj.name) + end + end + end + + function m.uniqueProjectIds(wks) local uuids = {} for prj in p.workspace.eachproject(wks) do From 368ef429769d64fe3feed2cf546e5101755b5b3a Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Thu, 13 Apr 2017 13:44:20 +0300 Subject: [PATCH 31/59] Respect copylocal for NuGet packages --- src/actions/vstudio/vs2005_csproj.lua | 8 ++- .../vstudio/cs2005/test_assembly_refs.lua | 62 +++++++++++++++++++ 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/actions/vstudio/vs2005_csproj.lua b/src/actions/vstudio/vs2005_csproj.lua index 20bd9ce6..207078f0 100644 --- a/src/actions/vstudio/vs2005_csproj.lua +++ b/src/actions/vstudio/vs2005_csproj.lua @@ -448,7 +448,13 @@ _x(2, '', path.getbasename(file)) _x(3, '%s', vstudio.path(prj, p.filename(prj.solution, string.format("packages\\%s.%s\\%s", id, packageAPIInfo.verbatimVersion or packageAPIInfo.version, file)))) - _p(3, 'True') + + if config.isCopyLocal(prj, package, true) then + _p(3, 'True') + else + _p(3, 'False') + end + _p(2, '') end end diff --git a/tests/actions/vstudio/cs2005/test_assembly_refs.lua b/tests/actions/vstudio/cs2005/test_assembly_refs.lua index 5602926b..6a68ceaa 100644 --- a/tests/actions/vstudio/cs2005/test_assembly_refs.lua +++ b/tests/actions/vstudio/cs2005/test_assembly_refs.lua @@ -197,3 +197,65 @@ ]] end + + +-- +-- NuGet packages should respect copylocal() and the NoCopyLocal flag. +-- + + function suite.nugetPackages_onNoCopyLocal() + dotnetframework "2.0" + nuget { "NUnit:3.6.1" } + flags { "NoCopyLocal" } + prepare() + test.capture [[ + + + packages\NUnit.3.6.1\lib\net20\nunit.framework.dll + False + + + packages\NUnit.3.6.1\lib\net20\NUnit.System.Linq.dll + False + + + ]] + end + + function suite.nugetPackages_onCopyLocalListExclusion() + dotnetframework "2.0" + nuget { "NUnit:3.6.1" } + copylocal { "SomeOtherProject" } + prepare() + test.capture [[ + + + packages\NUnit.3.6.1\lib\net20\nunit.framework.dll + False + + + packages\NUnit.3.6.1\lib\net20\NUnit.System.Linq.dll + False + + + ]] + end + + function suite.nugetPackages_onCopyLocalListInclusion() + dotnetframework "2.0" + nuget { "NUnit:3.6.1" } + copylocal { "NUnit:3.6.1" } + prepare() + test.capture [[ + + + packages\NUnit.3.6.1\lib\net20\nunit.framework.dll + True + + + packages\NUnit.3.6.1\lib\net20\NUnit.System.Linq.dll + True + + + ]] + end From cf82b2cf222778fe3d4562842d1d2409c3f53eaf Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Wed, 12 Apr 2017 13:20:17 +0300 Subject: [PATCH 32/59] Fix not all versions of NuGet packages being found If a package has a lot of versions, the NuGet API returns multiple "pages" of results, but we only looked at the first "page". This happened with the "NLog" package for example. --- src/actions/vstudio/vs2010_nuget.lua | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/actions/vstudio/vs2010_nuget.lua b/src/actions/vstudio/vs2010_nuget.lua index 465d5596..e16b1883 100644 --- a/src/actions/vstudio/vs2010_nuget.lua +++ b/src/actions/vstudio/vs2010_nuget.lua @@ -125,18 +125,24 @@ end if not response.items or #response.items == 0 then - p.error("Failed to understand NuGet API response (package '%s' contains no root-level items)", id) + p.error("Failed to understand NuGet API response (no pages for package '%s')", id) end - if not response.items[1].items or #response.items[1].items == 0 then - p.error("Failed to understand NuGet API response (root-level item for package '%s' contains no subitems)", id) + local items = {} + + for _, page in ipairs(response.items) do + if not page.items or #page.items == 0 then + p.error("Failed to understand NuGet API response (got a page with no items for package '%s')", id) end - local subitems = response.items[1].items + for _, item in ipairs(page.items) do + table.insert(items, item) + end + end local versions = {} - for _, item in ipairs(subitems) do + for _, item in ipairs(items) do if not item.catalogEntry then p.error("Failed to understand NuGet API response (subitem of package '%s' has no catalogEntry)", id) end @@ -159,7 +165,7 @@ p.error("'%s' is not a valid version for NuGet package '%s' (options are: %s)", version, id, options) end - for _, item in ipairs(subitems) do + for _, item in ipairs(items) do if item.catalogEntry.version == version then local response, err, code = http.get(item.catalogEntry["@id"]) From 067db7a6598f626b2a7203964f55e4e8c757fa4e Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Thu, 13 Apr 2017 14:03:54 +0300 Subject: [PATCH 33/59] Warn about NuGet package dependencies --- src/actions/vstudio/vs2010_nuget.lua | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/actions/vstudio/vs2010_nuget.lua b/src/actions/vstudio/vs2010_nuget.lua index e16b1883..ae9f305a 100644 --- a/src/actions/vstudio/vs2010_nuget.lua +++ b/src/actions/vstudio/vs2010_nuget.lua @@ -213,6 +213,14 @@ if #packageAPIInfo.packageEntries == 0 then p.error("NuGet package '%s' file listing is empty", id) end + + if response.frameworkAssemblyGroup then + p.warn("NuGet package '%s' may depend on .NET Framework assemblies - package dependencies are currently unimplemented", id) + end + end + + if response.dependencyGroups then + p.warn("NuGet package '%s' may depend on other packages - package dependencies are currently unimplemented", id) end break From 83e0229a2ae92340026318323727297dacf6e9cb Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Tue, 18 Apr 2017 00:41:48 +1000 Subject: [PATCH 34/59] Fixed issue with using startproject API in CodeLite - Added test to ensure this doesn't break again --- modules/codelite/codelite_workspace.lua | 7 +++++-- .../tests/test_codelite_workspace.lua | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/modules/codelite/codelite_workspace.lua b/modules/codelite/codelite_workspace.lua index 6ab4697f..dc2f63a4 100755 --- a/modules/codelite/codelite_workspace.lua +++ b/modules/codelite/codelite_workspace.lua @@ -44,8 +44,11 @@ local prjpath = p.filename(prj, ".project") prjpath = path.getrelative(prj.workspace.location, prjpath) - local active = iif(prj.name == wks.startproject, ' Active="Yes"', '') - _x(1, '', prj.name, prjpath, active) + if (prj.name == wks.startproject) then + _x(1, '', prj.name, prjpath) + else + _x(1, '', prj.name, prjpath) + end end, onbranch = function(n) diff --git a/modules/codelite/tests/test_codelite_workspace.lua b/modules/codelite/tests/test_codelite_workspace.lua index 0f2c0ff7..f63453bf 100644 --- a/modules/codelite/tests/test_codelite_workspace.lua +++ b/modules/codelite/tests/test_codelite_workspace.lua @@ -129,3 +129,24 @@ ]]) end + + + function suite.onActiveProject() + workspace("MyWorkspace") + startproject "MyProject" + prepare() + test.capture([[ + + + + + + + + + + + + + ]]) + end From dfee2c0184d4257135403f47d27b4ab6dcd1f513 Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Tue, 18 Apr 2017 01:13:20 +1000 Subject: [PATCH 35/59] Fixed erroneous escape usages in VS2010+ - Added tests for sensible escape usage locations (defines, not undefines or warnings) --- src/actions/vstudio/vs2010_vcxproj.lua | 10 +++++----- .../vstudio/vc2010/test_compile_settings.lua | 18 ++++++++++++++++++ .../vstudio/vc2010/test_nmake_props.lua | 13 +++++++++++++ 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index 9e33e54d..3996822c 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -1797,7 +1797,7 @@ function m.nmakePreprocessorDefinitions(cfg) if cfg.kind ~= p.NONE and #cfg.defines > 0 then local defines = table.concat(cfg.defines, ";") - defines = p.esc(defines) .. ";$(NMakePreprocessorDefinitions)" + defines = defines .. ";$(NMakePreprocessorDefinitions)" m.element('NMakePreprocessorDefinitions', nil, defines) end end @@ -1912,7 +1912,7 @@ if escapeQuotes then defines = defines:gsub('"', '\\"') end - defines = p.esc(defines) .. ";%%(PreprocessorDefinitions)" + defines = defines .. ";%%(PreprocessorDefinitions)" m.element('PreprocessorDefinitions', condition, defines) end end @@ -1924,7 +1924,7 @@ if escapeQuotes then undefines = undefines:gsub('"', '\\"') end - undefines = p.esc(undefines) .. ";%%(UndefinePreprocessorDefinitions)" + undefines = undefines .. ";%%(UndefinePreprocessorDefinitions)" m.element('UndefinePreprocessorDefinitions', condition, undefines) end end @@ -2142,7 +2142,7 @@ function m.disableSpecificWarnings(cfg, condition) if #cfg.disablewarnings > 0 then local warnings = table.concat(cfg.disablewarnings, ";") - warnings = p.esc(warnings) .. ";%%(DisableSpecificWarnings)" + warnings = warnings .. ";%%(DisableSpecificWarnings)" m.element('DisableSpecificWarnings', condition, warnings) end end @@ -2151,7 +2151,7 @@ function m.treatSpecificWarningsAsErrors(cfg, condition) if #cfg.fatalwarnings > 0 then local fatal = table.concat(cfg.fatalwarnings, ";") - fatal = p.esc(fatal) .. ";%%(TreatSpecificWarningsAsErrors)" + fatal = fatal .. ";%%(TreatSpecificWarningsAsErrors)" m.element('TreatSpecificWarningsAsErrors', condition, fatal) end end diff --git a/tests/actions/vstudio/vc2010/test_compile_settings.lua b/tests/actions/vstudio/vc2010/test_compile_settings.lua index 6e20a6f7..d9498fee 100644 --- a/tests/actions/vstudio/vc2010/test_compile_settings.lua +++ b/tests/actions/vstudio/vc2010/test_compile_settings.lua @@ -267,6 +267,24 @@ end +-- +-- If defines are specified with escapable characters, they should be escaped. +-- + + function suite.preprocessorDefinitions_onDefines() + premake.escaper(premake.vstudio.vs2010.esc) + defines { "&", "<", ">" } + prepare() + test.capture [[ + + NotUsing + Level3 + &;<;>;%(PreprocessorDefinitions) + ]] + premake.escaper(nil) + end + + -- -- If undefines are specified, the element should be added. -- diff --git a/tests/actions/vstudio/vc2010/test_nmake_props.lua b/tests/actions/vstudio/vc2010/test_nmake_props.lua index f46a0c6a..a34a0644 100644 --- a/tests/actions/vstudio/vc2010/test_nmake_props.lua +++ b/tests/actions/vstudio/vc2010/test_nmake_props.lua @@ -126,6 +126,19 @@ command 2 ]] end + function suite.onEscapedDefines() + premake.escaper(premake.vstudio.vs2010.esc) + defines { "&", "<", ">" } + prepare() + test.capture [[ + + $(OutDir)MyProject + &;<;>;$(NMakePreprocessorDefinitions) + + ]] + premake.escaper(nil) + end + function suite.onIncludeDirs() includedirs { "include/lua", "include/zlib" } prepare() From 713df1c9f3663823fc993c07c2b015198b8de582 Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Thu, 20 Apr 2017 01:04:10 +1000 Subject: [PATCH 36/59] Bootstrap makefile now cleans up previous builds before building --- Bootstrap.mak | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Bootstrap.mak b/Bootstrap.mak index d089654b..db0cc106 100644 --- a/Bootstrap.mak +++ b/Bootstrap.mak @@ -45,6 +45,9 @@ none: @echo " osx linux" mingw: $(SRC) + $(SILENT) rm -rf ./bin + $(SILENT) rm -rf ./build + $(SILENT) rm -rf ./obj mkdir -p build/bootstrap $(CC) -o build/bootstrap/premake_bootstrap -DPREMAKE_NO_BUILTIN_SCRIPTS -I"$(LUA_DIR)" $? -lole32 ./build/bootstrap/premake_bootstrap embed @@ -52,6 +55,9 @@ mingw: $(SRC) $(MAKE) -C build/bootstrap osx: $(SRC) + $(SILENT) rm -rf ./bin + $(SILENT) rm -rf ./build + $(SILENT) rm -rf ./obj mkdir -p build/bootstrap $(CC) -o build/bootstrap/premake_bootstrap -DPREMAKE_NO_BUILTIN_SCRIPTS -DLUA_USE_MACOSX -I"$(LUA_DIR)" -framework CoreServices -framework Foundation -framework Security $? ./build/bootstrap/premake_bootstrap embed @@ -59,6 +65,9 @@ osx: $(SRC) $(MAKE) -C build/bootstrap -j`getconf _NPROCESSORS_ONLN` linux: $(SRC) + $(SILENT) rm -rf ./bin + $(SILENT) rm -rf ./build + $(SILENT) rm -rf ./obj mkdir -p build/bootstrap $(CC) -o build/bootstrap/premake_bootstrap -DPREMAKE_NO_BUILTIN_SCRIPTS -DLUA_USE_POSIX -DLUA_USE_DLOPEN -I"$(LUA_DIR)" $? -lm -ldl -lrt ./build/bootstrap/premake_bootstrap embed @@ -66,6 +75,9 @@ linux: $(SRC) $(MAKE) -C build/bootstrap -j`getconf _NPROCESSORS_ONLN` bsd: $(SRC) + $(SILENT) rm -rf ./bin + $(SILENT) rm -rf ./build + $(SILENT) rm -rf ./obj mkdir -p build/bootstrap $(CC) -o build/bootstrap/premake_bootstrap -DPREMAKE_NO_BUILTIN_SCRIPTS -DLUA_USE_POSIX -DLUA_USE_DLOPEN -I"$(LUA_DIR)" $? -lm ./build/bootstrap/premake_bootstrap embed @@ -73,6 +85,9 @@ bsd: $(SRC) $(MAKE) -C build/bootstrap -j`getconf _NPROCESSORS_ONLN` windows-base: $(SRC) + $(SILENT) if exist .\bin rmdir /s /q .\bin + $(SILENT) if exist .\build rmdir /s /q .\build + $(SILENT) if exist .\obj rmdir /s /q .\obj if not exist build\bootstrap (mkdir build\bootstrap) cl /Fo.\build\bootstrap\ /Fe.\build\bootstrap\premake_bootstrap.exe /DPREMAKE_NO_BUILTIN_SCRIPTS /I"$(LUA_DIR)" user32.lib ole32.lib advapi32.lib $** .\build\bootstrap\premake_bootstrap.exe embed From 537392428d54e225933bed1733809c29e90b6b6c Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Thu, 20 Apr 2017 02:05:27 +1000 Subject: [PATCH 37/59] os.translateCommands now supports multiple tokens --- src/base/os.lua | 25 +++++++++++++++++-------- tests/base/test_os.lua | 7 +++++++ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/base/os.lua b/src/base/os.lua index f52bf538..bd1aa547 100644 --- a/src/base/os.lua +++ b/src/base/os.lua @@ -535,15 +535,24 @@ end local processOne = function(cmd) - local token = cmd:match("^{.+}") - if token then - token = token:sub(2, #token - 1):lower() - local args = cmd:sub(#token + 4) - local func = map[token] or os.commandTokens["_"][token] - if func then - cmd = func(args) + local i, j, prev + repeat + i, j = cmd:find("{.-}") + if i then + if i == prev then + break + end + + local token = cmd:sub(i + 1, j - 1):lower() + local args = cmd:sub(j + 2) + local func = map[token] or os.commandTokens["_"][token] + if func then + cmd = cmd:sub(1, i -1) .. func(args) + end + + prev = i end - end + until i == nil return cmd end diff --git a/tests/base/test_os.lua b/tests/base/test_os.lua index c3748546..98e5ddad 100644 --- a/tests/base/test_os.lua +++ b/tests/base/test_os.lua @@ -177,6 +177,13 @@ test.isequal("test a b", os.translateCommands("{COPY} a b", "test")) end + function suite.translateCommand_callsProcessor_multipleTokens() + os.commandTokens.test = { + copy = function(value) return "test " .. value end + } + test.isequal("test a b; test c d; test e f;", os.translateCommands("{COPY} a b; {COPY} c d; {COPY} e f;", "test")) + end + -- -- os.translateCommand() windows COPY tests -- From 438949a7a188a0c850328a8342cfc0f47ce00176 Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Fri, 21 Apr 2017 02:37:31 +1000 Subject: [PATCH 38/59] Updated packaging script - Find all occurrences of files wanting to be deleted rather than assuming locations - Added vs2017 and bsd to project file generation --- scripts/package.lua | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/package.lua b/scripts/package.lua index bf354325..8cd1b71d 100644 --- a/scripts/package.lua +++ b/scripts/package.lua @@ -127,18 +127,16 @@ print("Cleaning up the source tree...") os.rmdir("packages") + os.rmdir(".git") - local modules = table.join(".", os.matchdirs("modules/*")) - for _, module in ipairs(modules) do - for _, name in ipairs { ".git" } do - os.rmdir(path.join(module, name)) - end - for _, name in ipairs { ".DS_Store", ".git", ".gitignore", ".gitmodules", ".travis.yml", ".editorconfig", "Bootstrap.mak" } do - os.remove(path.join(module, name)) + local removelist = { ".DS_Store", ".git", ".gitignore", ".gitmodules", ".travis.yml", ".editorconfig", "appveyor.yml", "Bootstrap.mak" } + for _, removeitem in ipairs(removelist) do + local founditems = os.matchfiles("**" .. removeitem) + for _, item in ipairs(founditems) do + os.remove(item) end end - -- -- Generate a source package. -- @@ -152,9 +150,11 @@ if kind == "source" then execQuiet("premake5 /to=build/vs2012 vs2012") execQuiet("premake5 /to=build/vs2013 vs2013") execQuiet("premake5 /to=build/vs2015 vs2015") + execQuiet("premake5 /to=build/vs2017 vs2017") execQuiet("premake5 /to=build/gmake.windows /os=windows gmake") execQuiet("premake5 /to=build/gmake.unix /os=linux gmake") execQuiet("premake5 /to=build/gmake.macosx /os=macosx gmake") + execQuiet("premake5 /to=build/gmake.bsd /os=bsd gmake") print("Creating source code package...") os.chdir("..") From 5b688cac93a2b1ab50ab851e7ccfeb7b5ac9b970 Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Mon, 24 Apr 2017 00:42:48 +1000 Subject: [PATCH 39/59] CompileAs element handles C++ now - Added tests --- src/actions/vstudio/vs2010_vcxproj.lua | 2 + .../vstudio/vc2010/test_compile_settings.lua | 38 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index 9e33e54d..be901699 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -1217,6 +1217,8 @@ function m.compileAs(cfg) if p.languages.isc(cfg.language) then m.element("CompileAs", nil, "CompileAsC") + elseif p.languages.iscpp(cfg.language) then + m.element("CompileAs", nil, "CompileAsCpp") end end diff --git a/tests/actions/vstudio/vc2010/test_compile_settings.lua b/tests/actions/vstudio/vc2010/test_compile_settings.lua index 6e20a6f7..e17ed9de 100644 --- a/tests/actions/vstudio/vc2010/test_compile_settings.lua +++ b/tests/actions/vstudio/vc2010/test_compile_settings.lua @@ -37,6 +37,7 @@ NotUsing Level3 Disabled + CompileAsCpp ]] end @@ -222,6 +223,7 @@ NotUsing Level3 Disabled + CompileAsCpp ]] end @@ -234,6 +236,7 @@ NotUsing Level3 Disabled + CompileAsCpp ]] end @@ -440,6 +443,7 @@ NotUsing Level3 Disabled + CompileAsCpp ]] end @@ -453,6 +457,7 @@ Level3 None Disabled + CompileAsCpp ]] end @@ -466,6 +471,7 @@ Level3 EditAndContinue Disabled + CompileAsCpp ]] end @@ -902,6 +908,7 @@ NotUsing Level3 Disabled + CompileAsCpp ]] end @@ -990,3 +997,34 @@ true ]] end + + + +-- +-- Check handling of the language api +-- + function suite.onLanguageC() + language 'C' + prepare() + test.capture [[ + + NotUsing + Level3 + Disabled + CompileAsC + + ]] + end + + function suite.onLanguageCpp() + language 'C++' + prepare() + test.capture [[ + + NotUsing + Level3 + Disabled + CompileAsCpp + + ]] + end From 25de4e419ecde389347b7dc080f2ef922eb862bc Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Tue, 25 Apr 2017 01:51:04 +1000 Subject: [PATCH 40/59] Added proxy URL to http options --- src/host/curl_utils.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/host/curl_utils.c b/src/host/curl_utils.c index 8cc6b025..e4a2919a 100644 --- a/src/host/curl_utils.c +++ b/src/host/curl_utils.c @@ -134,6 +134,10 @@ CURL* curlRequest(lua_State* L, curl_state* state, int optionsIndex, int progres { curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, (long)luaL_checknumber(L, -1)); } + else if (!strcmp(key, "proxyurl") && lua_isstring(L, -1)) + { + curl_easy_setopt(curl, CURLOPT_PROXY, luaL_checkstring(L, -1)); + } // pop the value, leave the key for lua_next lua_pop(L, 1); From 8ac4955b22a912877df3f8fd6ea7be74f86da845 Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Tue, 25 Apr 2017 01:37:46 +1000 Subject: [PATCH 41/59] Fixed various issues with compiling with VS2012 --- src/host/buffered_io.c | 7 ++++--- src/host/os_chdir.c | 4 ++-- src/host/os_getversion.c | 4 ++-- src/host/os_isfile.c | 8 +++++--- src/host/os_islink.c | 3 ++- src/host/os_match.c | 3 ++- 6 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/host/buffered_io.c b/src/host/buffered_io.c index 160bbccf..018402be 100644 --- a/src/host/buffered_io.c +++ b/src/host/buffered_io.c @@ -16,7 +16,7 @@ void buffer_init(Buffer* b) b->data = NULL; } -void buffer_destroy(Buffer* b) +void buffer_destroy(Buffer* b) { free(b->data); b->capacity = 0; @@ -53,12 +53,13 @@ void buffer_puts(Buffer* b, const void* ptr, size_t len) b->length += len; } -void buffer_printf(Buffer* b, const char *fmt, ...) +void buffer_printf(Buffer* b, const char *fmt, ...) { char text[2048]; + int len; va_list args; va_start(args, fmt); - int len = vsnprintf(text, sizeof(text) - 1, fmt, args); + len = vsnprintf(text, sizeof(text) - 1, fmt, args); va_end(args); buffer_puts(b, text, len); } diff --git a/src/host/os_chdir.c b/src/host/os_chdir.c index 28aa0fcd..b51292af 100644 --- a/src/host/os_chdir.c +++ b/src/host/os_chdir.c @@ -11,8 +11,6 @@ int do_chdir(lua_State* L, const char* path) { int z; - (void)(L); /* warning: unused parameter */ - #if PLATFORM_WINDOWS wchar_t wide_buffer[PATH_MAX]; if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wide_buffer, PATH_MAX) == 0) @@ -23,6 +21,8 @@ int do_chdir(lua_State* L, const char* path) z = SetCurrentDirectoryW(wide_buffer); #else + (void)(L); /* warning: unused parameter */ + z = !chdir(path); #endif diff --git a/src/host/os_getversion.c b/src/host/os_getversion.c index 970ff237..40b0c83c 100644 --- a/src/host/os_getversion.c +++ b/src/host/os_getversion.c @@ -67,7 +67,7 @@ int getKernelVersion(struct OsVersionInfo* info) { void* fixedInfoPtr; UINT fixedInfoSize; - if (VerQueryValueA(data, "\\", &fixedInfoPtr, &fixedInfoSize)) + if (VerQueryValueA(data, "\\", &fixedInfoPtr, &fixedInfoSize)) { VS_FIXEDFILEINFO* fileInfo = (VS_FIXEDFILEINFO*)fixedInfoPtr; info->majorversion = HIWORD(fileInfo->dwProductVersionMS); @@ -82,10 +82,10 @@ int getKernelVersion(struct OsVersionInfo* info) int getversion(struct OsVersionInfo* info) { + HKEY key; info->description = "Windows"; // First get a friendly product name from the registry. - HKEY key; if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &key) == ERROR_SUCCESS) { char value[512]; diff --git a/src/host/os_isfile.c b/src/host/os_isfile.c index 2bad6f04..c2a10768 100644 --- a/src/host/os_isfile.c +++ b/src/host/os_isfile.c @@ -18,10 +18,9 @@ int os_isfile(lua_State* L) int do_isfile(lua_State* L, const char* filename) { - (void)(L); /* warning: unused parameter */ - #if PLATFORM_WINDOWS wchar_t wide_path[PATH_MAX]; + DWORD attrib; if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, wide_path, PATH_MAX) == 0) { @@ -29,13 +28,16 @@ int do_isfile(lua_State* L, const char* filename) return lua_error(L); } - DWORD attrib = GetFileAttributesW(wide_path); + attrib = GetFileAttributesW(wide_path); if (attrib != INVALID_FILE_ATTRIBUTES) { return (attrib & FILE_ATTRIBUTE_DIRECTORY) == 0; } #else struct stat buf; + + (void)(L); /* warning: unused parameter */ + if (stat(filename, &buf) == 0) { return ((buf.st_mode & S_IFDIR) == 0); diff --git a/src/host/os_islink.c b/src/host/os_islink.c index 1c2dee91..4ce0902d 100644 --- a/src/host/os_islink.c +++ b/src/host/os_islink.c @@ -15,13 +15,14 @@ int os_islink(lua_State* L) #if PLATFORM_WINDOWS { wchar_t wide_path[PATH_MAX]; + DWORD attr; if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wide_path, PATH_MAX) == 0) { lua_pushstring(L, "unable to encode path"); return lua_error(L); } - DWORD attr = GetFileAttributesW(wide_path); + attr = GetFileAttributesW(wide_path); if (attr != INVALID_FILE_ATTRIBUTES) { lua_pushboolean(L, (attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0); return 1; diff --git a/src/host/os_match.c b/src/host/os_match.c index 2a25df68..a60e64d7 100644 --- a/src/host/os_match.c +++ b/src/host/os_match.c @@ -21,6 +21,7 @@ typedef struct struct_MatchInfo int os_matchstart(lua_State* L) { const char* mask = luaL_checkstring(L, 1); + MatchInfo* m; wchar_t wide_mask[PATH_MAX]; if (MultiByteToWideChar(CP_UTF8, 0, mask, -1, wide_mask, PATH_MAX) == 0) @@ -29,7 +30,7 @@ int os_matchstart(lua_State* L) return lua_error(L); } - MatchInfo* m = (MatchInfo*)malloc(sizeof(MatchInfo)); + m = (MatchInfo*)malloc(sizeof(MatchInfo)); m->handle = FindFirstFileW(wide_mask, &m->entry); m->is_first = 1; From 9c09a7142f7b3edacdaeb0566382a0ff61ae8e85 Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Tue, 25 Apr 2017 02:33:52 +1000 Subject: [PATCH 42/59] Fixed issue with the OBJDIR value not being escaped --- src/actions/make/_make.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/actions/make/_make.lua b/src/actions/make/_make.lua index b1803ac4..7da88ec9 100644 --- a/src/actions/make/_make.lua +++ b/src/actions/make/_make.lua @@ -232,7 +232,7 @@ --------------------------------------------------------------------------- function make.objdir(cfg) - _x(' OBJDIR = %s', project.getrelative(cfg.project, cfg.objdir)) + _x(' OBJDIR = %s', premake.esc(project.getrelative(cfg.project, cfg.objdir))) end From 5f589ad5a66a4b51b62cbcaf42119a52c1c3b2d4 Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Tue, 11 Apr 2017 13:39:25 -0700 Subject: [PATCH 43/59] replaced: os.get() -> os.target() os.is() -> os.istarget() _OS -> _TARGET_OS added: os.current() os.iscurrent() --- modules/self-test/test_runner.lua | 4 +- modules/xcode/_preload.lua | 2 +- modules/xcode/tests/test_xcode4_project.lua | 2 +- modules/xcode/tests/test_xcode_project.lua | 2 +- scripts/package.lua | 6 +- src/actions/make/make_csharp.lua | 2 +- src/actions/vstudio/vs2005.lua | 2 +- src/actions/vstudio/vs2008.lua | 2 +- src/actions/vstudio/vs2010.lua | 2 +- src/actions/vstudio/vs2012.lua | 2 +- src/actions/vstudio/vs2013.lua | 2 +- src/actions/vstudio/vs2015.lua | 2 +- src/actions/vstudio/vs2017.lua | 2 +- src/base/action.lua | 8 ++- src/base/moduledownloader.lua | 2 +- src/base/os.lua | 65 ++++++++++++++++---- src/base/oven.lua | 6 +- src/host/os_current.c | 13 ++++ src/host/premake.c | 3 +- src/host/premake.h | 1 + src/tools/dotnet.lua | 2 +- tests/actions/make/cpp/test_make_linking.lua | 6 +- tests/actions/make/cs/test_response.lua | 4 +- tests/base/test_os.lua | 26 ++++---- tests/config/test_links.lua | 2 +- tests/config/test_targetinfo.lua | 4 +- tests/project/test_getconfig.lua | 6 +- tests/tools/test_dotnet.lua | 4 +- 28 files changed, 122 insertions(+), 62 deletions(-) create mode 100644 src/host/os_current.c diff --git a/modules/self-test/test_runner.lua b/modules/self-test/test_runner.lua index 84b0a2b7..df349593 100644 --- a/modules/self-test/test_runner.lua +++ b/modules/self-test/test_runner.lua @@ -108,7 +108,7 @@ hooks.action = _ACTION hooks.options = _OPTIONS - hooks.os = _OS + hooks.targetOs = _TARGET_OS hooks.io_open = io.open hooks.io_output = io.output @@ -151,7 +151,7 @@ function _.removeTestingHooks(hooks) _ACTION = hooks.action _OPTIONS = hooks.options - _OS = hooks.os + _TARGET_OS = hooks.targetOs io.open = hooks.io_open io.output = hooks.io_output diff --git a/modules/xcode/_preload.lua b/modules/xcode/_preload.lua index 4c1cc1b2..412974af 100644 --- a/modules/xcode/_preload.lua +++ b/modules/xcode/_preload.lua @@ -35,7 +35,7 @@ -- Xcode always uses Mac OS X path and naming conventions - os = "macosx", + targetos = "macosx", -- The capabilities of this action diff --git a/modules/xcode/tests/test_xcode4_project.lua b/modules/xcode/tests/test_xcode4_project.lua index 9729cb37..bf4b3961 100644 --- a/modules/xcode/tests/test_xcode4_project.lua +++ b/modules/xcode/tests/test_xcode4_project.lua @@ -48,7 +48,7 @@ end function suite.setup() - _OS = "macosx" + _TARGET_OS = "macosx" _ACTION = "xcode4" io.eol = "\n" xcode.used_ids = { } -- reset the list of generated IDs diff --git a/modules/xcode/tests/test_xcode_project.lua b/modules/xcode/tests/test_xcode_project.lua index 1f13f90b..de9d02e1 100644 --- a/modules/xcode/tests/test_xcode_project.lua +++ b/modules/xcode/tests/test_xcode_project.lua @@ -19,7 +19,7 @@ end function suite.setup() - _OS = "macosx" + _TARGET_OS = "macosx" _ACTION = "xcode4" premake.eol("\n") xcode.used_ids = { } -- reset the list of generated IDs diff --git a/scripts/package.lua b/scripts/package.lua index 8cd1b71d..4c4c1643 100644 --- a/scripts/package.lua +++ b/scripts/package.lua @@ -60,7 +60,7 @@ local pkgName = "premake-" .. version local pkgExt = ".zip" - if not os.is("windows") and kind == "binary" then + if not os.istarget("windows") and kind == "binary" then pkgExt = ".tar.gz" end @@ -180,8 +180,8 @@ if kind == "binary" then os.chdir("bin/release") - local name = string.format("%s-%s%s", pkgName, os.get(), pkgExt) - if os.is("windows") then + local name = string.format("%s-%s%s", pkgName, os.current(), pkgExt) + if os.iscurrent("windows") then execQuiet("zip -9 %s premake5.exe", name) else execQuiet("tar czvf %s premake5", name) diff --git a/src/actions/make/make_csharp.lua b/src/actions/make/make_csharp.lua index 7a7e3fbd..01d622a0 100644 --- a/src/actions/make/make_csharp.lua +++ b/src/actions/make/make_csharp.lua @@ -200,7 +200,7 @@ _x('\t$(SILENT) if exist $(RESPONSE) del %s', path.translate(response, '\\')) _p('endif') - local sep = os.is("windows") and "\\" or "/" + local sep = os.istarget("windows") and "\\" or "/" local tr = project.getsourcetree(prj) premake.tree.traverse(tr, { onleaf = function(node, depth) diff --git a/src/actions/vstudio/vs2005.lua b/src/actions/vstudio/vs2005.lua index 2a7ebc88..71a9a69b 100644 --- a/src/actions/vstudio/vs2005.lua +++ b/src/actions/vstudio/vs2005.lua @@ -95,7 +95,7 @@ -- Visual Studio always uses Windows path and naming conventions - os = "windows", + targetos = "windows", -- The capabilities of this action diff --git a/src/actions/vstudio/vs2008.lua b/src/actions/vstudio/vs2008.lua index afe3e49a..81116e00 100644 --- a/src/actions/vstudio/vs2008.lua +++ b/src/actions/vstudio/vs2008.lua @@ -22,7 +22,7 @@ -- Visual Studio always uses Windows path and naming conventions - os = "windows", + targetos = "windows", -- The capabilities of this action diff --git a/src/actions/vstudio/vs2010.lua b/src/actions/vstudio/vs2010.lua index 4cd57f91..7445c1e3 100644 --- a/src/actions/vstudio/vs2010.lua +++ b/src/actions/vstudio/vs2010.lua @@ -118,7 +118,7 @@ -- Visual Studio always uses Windows path and naming conventions - os = "windows", + targetos = "windows", -- The capabilities of this action diff --git a/src/actions/vstudio/vs2012.lua b/src/actions/vstudio/vs2012.lua index 4f46dc56..64653f68 100644 --- a/src/actions/vstudio/vs2012.lua +++ b/src/actions/vstudio/vs2012.lua @@ -24,7 +24,7 @@ -- Visual Studio always uses Windows path and naming conventions - os = "windows", + targetos = "windows", -- The capabilities of this action diff --git a/src/actions/vstudio/vs2013.lua b/src/actions/vstudio/vs2013.lua index 558f02bc..c0edb028 100644 --- a/src/actions/vstudio/vs2013.lua +++ b/src/actions/vstudio/vs2013.lua @@ -26,7 +26,7 @@ -- Visual Studio always uses Windows path and naming conventions - os = "windows", + targetos = "windows", -- The capabilities of this action diff --git a/src/actions/vstudio/vs2015.lua b/src/actions/vstudio/vs2015.lua index 88ab8e5e..f5754238 100644 --- a/src/actions/vstudio/vs2015.lua +++ b/src/actions/vstudio/vs2015.lua @@ -26,7 +26,7 @@ -- Visual Studio always uses Windows path and naming conventions - os = "windows", + targetos = "windows", -- The capabilities of this action diff --git a/src/actions/vstudio/vs2017.lua b/src/actions/vstudio/vs2017.lua index 0d5617c3..4afc9a1a 100644 --- a/src/actions/vstudio/vs2017.lua +++ b/src/actions/vstudio/vs2017.lua @@ -26,7 +26,7 @@ -- Visual Studio always uses Windows path and naming conventions - os = "windows", + targetos = "windows", -- The capabilities of this action diff --git a/src/base/action.lua b/src/base/action.lua index c403742c..b9ff31f8 100644 --- a/src/base/action.lua +++ b/src/base/action.lua @@ -61,6 +61,12 @@ error(string.format('action "%s" needs a %s', name, missing), 3) end + if act.os ~= nil then + premake.warnOnce(act.trigger, "action '" .. act.trigger .. "' sets 'os' field, which is deprecated, use 'targetos' instead.") + act.targetos = act.os + act.os = nil + end + action._list[act.trigger] = act end @@ -212,7 +218,7 @@ -- Some actions imply a particular operating system local act = action.get(name) if act then - _OS = act.os or _OS + _TARGET_OS = act.targetos or _TARGET_OS end -- Some are implemented in standalone modules diff --git a/src/base/moduledownloader.lua b/src/base/moduledownloader.lua index 30c8c7d7..55b76950 100644 --- a/src/base/moduledownloader.lua +++ b/src/base/moduledownloader.lua @@ -23,7 +23,7 @@ -- get current user. local user = 'UNKNOWN' - if os.get() == 'windows' then + if os.iscurrent('windows') then user = os.getenv('USERNAME') or user else user = os.getenv('LOGNAME') or user diff --git a/src/base/os.lua b/src/base/os.lua index bd1aa547..82912481 100644 --- a/src/base/os.lua +++ b/src/base/os.lua @@ -69,14 +69,14 @@ local path, formats -- assemble a search path, depending on the platform - if os.is("windows") then + if os.istarget("windows") then formats = { "%s.dll", "%s" } path = os.getenv("PATH") or "" - elseif os.is("haiku") then + elseif os.istarget("haiku") then formats = { "lib%s.so", "%s.so" } path = os.getenv("LIBRARY_PATH") or "" else - if os.is("macosx") then + if os.istarget("macosx") then formats = { "lib%s.dylib", "%s.dylib" } path = os.getenv("DYLD_LIBRARY_PATH") or "" else @@ -100,7 +100,7 @@ table.insert(formats, "%s") path = path or "" local archpath = "/lib:/usr/lib:/usr/local/lib" - if os.is64bit() and not os.is("macosx") then + if os.is64bit() and not os.istarget("macosx") then archpath = "/lib64:/usr/lib64/:usr/local/lib64" .. ":" .. archpath end if (#path > 0) then @@ -134,26 +134,65 @@ end +-- +-- Retrieve the current target operating system ID string. +-- --- --- Retrieve the current operating system ID string. --- + function os.target() + return _OPTIONS.os or _TARGET_OS + end function os.get() - return _OPTIONS.os or _OS + premake.warnOnce("os.get", "os.get() is deprecated, use 'os.target()' or 'os.current()'.") + return os.target() end + -- deprecate _OS + _G_metatable = { + __index = function(t, k) + if (k == '_OS') then + premake.warnOnce("_OS+get", "_OS is deprecated, use '_TARGET_OS'.") + return rawget(t, "_TARGET_OS") + else + return rawget(t, k) + end + end, + + __newindex = function(t, k, v) + if (k == '_OS') then + premake.warnOnce("_OS+set", "_OS is deprecated, use '_TARGET_OS'.") + rawset(t, "_TARGET_OS", v) + else + rawset(t, k, v) + end + end + } + setmetatable(_G, _G_metatable) + -- --- Check the current operating system; may be set with the /os command line flag. +-- Check the current target operating system; may be set with the /os command line flag. -- + function os.istarget(id) + return (os.target():lower() == id:lower()) + end + function os.is(id) - return (os.get():lower() == id:lower()) + premake.warnOnce("os.is", "os.is() is deprecated, use 'os.istarget()' or 'os.iscurrent()'.") + return os.istarget(id) end +-- +-- Check the current executing operating system. +-- + + function os.iscurrent(id) + return (os.current():lower() == id:lower()) + end + --- -- Determine if a directory exists on the file system, and that it is a @@ -219,9 +258,9 @@ else -- Identify the system local arch - if _OS == "windows" then + if os.iscurrent("windows") then arch = os.getenv("PROCESSOR_ARCHITECTURE") - elseif _OS == "macosx" then + elseif os.iscurrent("macosx") then arch = os.outputof("echo $HOSTTYPE") else arch = os.outputof("uname -m") @@ -529,7 +568,7 @@ } function os.translateCommands(cmd, map) - map = map or os.get() + map = map or os.target() if type(map) == "string" then map = os.commandTokens[map] or os.commandTokens["_"] end diff --git a/src/base/oven.lua b/src/base/oven.lua index a781ac91..d0a8197d 100644 --- a/src/base/oven.lua +++ b/src/base/oven.lua @@ -63,7 +63,7 @@ context.addFilter(self, "_ACTION", _ACTION) context.addFilter(self, "action", _ACTION) - self.system = self.system or p.action.current().os or os.get() + self.system = self.system or p.action.current().targetos or os.target() context.addFilter(self, "system", self.system) -- Add command line options to the filtering options @@ -204,7 +204,7 @@ -- Now filter on the current system and architecture, allowing the -- values that might already in the context to override my defaults. - self.system = self.system or p.action.current().os or os.get() + self.system = self.system or p.action.current().targetos or os.target() context.addFilter(self, "system", self.system) context.addFilter(self, "architecture", self.architecture) @@ -528,7 +528,7 @@ -- More than a convenience; this is required to work properly with -- external Visual Studio project files. - local system = p.action.current().os or os.get() + local system = p.action.current().targetos or os.target() local architecture = nil local toolset = nil diff --git a/src/host/os_current.c b/src/host/os_current.c new file mode 100644 index 00000000..9869e986 --- /dev/null +++ b/src/host/os_current.c @@ -0,0 +1,13 @@ +/** + * \file os_current.c + * \brief Get the current OS we're executing on. + * \author Copyright (c) 2014-2017 Tom van Dijck, Jason Perkins and the Premake project + */ + +#include "premake.h" + +int os_current(lua_State* L) +{ + lua_pushstring(L, PLATFORM_STRING); + return 1; +} diff --git a/src/host/premake.c b/src/host/premake.c index 8b03b2f0..60cc2b0b 100644 --- a/src/host/premake.c +++ b/src/host/premake.c @@ -58,6 +58,7 @@ static const luaL_Reg os_functions[] = { { "chdir", os_chdir }, { "chmod", os_chmod }, { "copyfile", os_copyfile }, + { "current", os_current }, { "_is64bit", os_is64bit }, { "isdir", os_isdir }, { "getcwd", os_getcwd }, @@ -153,7 +154,7 @@ int premake_init(lua_State* L) /* set the OS platform variable */ lua_pushstring(L, PLATFORM_STRING); - lua_setglobal(L, "_OS"); + lua_setglobal(L, "_TARGET_OS"); /* find the user's home directory */ value = getenv("HOME"); diff --git a/src/host/premake.h b/src/host/premake.h index c8bb3f23..64f951ec 100644 --- a/src/host/premake.h +++ b/src/host/premake.h @@ -102,6 +102,7 @@ int path_wildcards(lua_State* L); int os_chdir(lua_State* L); int os_chmod(lua_State* L); int os_copyfile(lua_State* L); +int os_current(lua_State* L); int os_getcwd(lua_State* L); int os_getpass(lua_State* L); int os_getWindowsRegistry(lua_State* L); diff --git a/src/tools/dotnet.lua b/src/tools/dotnet.lua index 63748727..ffa02809 100644 --- a/src/tools/dotnet.lua +++ b/src/tools/dotnet.lua @@ -222,7 +222,7 @@ } if tool == "csc" then - local toolset = _OPTIONS.dotnet or iif(os.is(premake.WINDOWS), "msnet", "mono") + local toolset = _OPTIONS.dotnet or iif(os.istarget("windows"), "msnet", "mono") return compilers[toolset] else return "resgen" diff --git a/tests/actions/make/cpp/test_make_linking.lua b/tests/actions/make/cpp/test_make_linking.lua index 1118c251..0b952638 100644 --- a/tests/actions/make/cpp/test_make_linking.lua +++ b/tests/actions/make/cpp/test_make_linking.lua @@ -16,7 +16,7 @@ local wks, prj function suite.setup() - _OS = "linux" + _TARGET_OS = "linux" wks, prj = test.createWorkspace() end @@ -41,7 +41,7 @@ end function suite.links_onMacOSXCppSharedLib() - _OS = "macosx" + _TARGET_OS = "macosx" kind "SharedLib" prepare { "ldFlags", "linkCmd" } test.capture [[ @@ -169,7 +169,7 @@ end function suite.links_onMacOSXSiblingSharedLib() - _OS = "macosx" + _TARGET_OS = "macosx" links "MyProject2" flags { "RelativeLinks" } diff --git a/tests/actions/make/cs/test_response.lua b/tests/actions/make/cs/test_response.lua index 64ee427c..d766d45a 100644 --- a/tests/actions/make/cs/test_response.lua +++ b/tests/actions/make/cs/test_response.lua @@ -55,7 +55,7 @@ $(TARGET): $(SOURCES) $(EMBEDFILES) $(DEPENDS) $(RESPONSE) end function suite.listResponseRulesPosix() - _OS = "linux" + _TARGET_OS = "linux" suite.listResponseRules() test.capture [[ $(RESPONSE): MyProject.make @@ -72,7 +72,7 @@ endif end function suite.listResponseRulesWindows() - _OS = "windows" + _TARGET_OS = "windows" suite.listResponseRules() test.capture [[ $(RESPONSE): MyProject.make diff --git a/tests/base/test_os.lua b/tests/base/test_os.lua index 98e5ddad..99931e29 100644 --- a/tests/base/test_os.lua +++ b/tests/base/test_os.lua @@ -23,9 +23,9 @@ -- function suite.findlib_FindSystemLib() - if os.is("windows") then + if os.istarget("windows") then test.istrue(os.findlib("user32")) - elseif os.is("haiku") then + elseif os.istarget("haiku") then test.istrue(os.findlib("root")) else test.istrue(os.findlib("m")) @@ -143,10 +143,10 @@ -- Check if outputof returns the command exit code -- in addition of the command output function suite.outputof_commandExitCode() - if os.is("macosx") - or os.is("linux") - or os.is("solaris") - or os.is("bsd") + if os.istarget("macosx") + or os.istarget("linux") + or os.istarget("solaris") + or os.istarget("bsd") then -- Assumes 'true' and 'false' commands exist -- which should be the case on all *nix platforms @@ -232,48 +232,48 @@ -- os.getWindowsRegistry windows tests -- function suite.getreg_nonExistentValue() - if os.is("windows") then + if os.iscurrent("windows") then local x = os.getWindowsRegistry("HKCU:Should\\Not\\Exist\\At\\All") test.isequal(nil, x) end end function suite.getreg_nonExistentDefaultValue() - if os.is("windows") then + if os.iscurrent("windows") then local x = os.getWindowsRegistry("HKCU:Should\\Not\\Exist\\At\\All\\") test.isequal(nil, x) end end function suite.getreg_noSeparators() - if os.is("windows") then + if os.iscurrent("windows") then os.getWindowsRegistry("HKCU:ShouldNotExistAtAll") end end function suite.getreg_namedValue() - if os.is("windows") then + if os.iscurrent("windows") then local x = os.getWindowsRegistry("HKCU:Environment\\TEMP") test.istrue(x ~= nil) end end function suite.getreg_namedValueOptSeparator() - if os.is("windows") then + if os.iscurrent("windows") then local x = os.getWindowsRegistry("HKCU:\\Environment\\TEMP") test.istrue(x ~= nil) end end function suite.getreg_defaultValue() - if os.is("windows") then + if os.iscurrent("windows") then local x = os.getWindowsRegistry("HKLM:SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Minimal\\AppInfo\\") test.isequal("Service", x) end end --- +-- -- os.getversion tests. -- diff --git a/tests/config/test_links.lua b/tests/config/test_links.lua index c4034092..67f68a33 100755 --- a/tests/config/test_links.lua +++ b/tests/config/test_links.lua @@ -16,7 +16,7 @@ function suite.setup() premake.action.set("test") - _OS = "windows" + _TARGET_OS = "windows" wks, prj = test.createWorkspace() end diff --git a/tests/config/test_targetinfo.lua b/tests/config/test_targetinfo.lua index 2c7617b8..bad4b393 100755 --- a/tests/config/test_targetinfo.lua +++ b/tests/config/test_targetinfo.lua @@ -252,7 +252,7 @@ -- function suite.appUsesExe_onDotNet() - _OS = "macosx" + _TARGET_OS = "macosx" language "C#" i = prepare() test.isequal("MyProject.exe", i.name) @@ -265,7 +265,7 @@ -- function suite.appUsesExe_onDotNet() - _OS = "macosx" + _TARGET_OS = "macosx" language "C#" kind "SharedLib" i = prepare() diff --git a/tests/project/test_getconfig.lua b/tests/project/test_getconfig.lua index 34c55cb5..78b4f447 100755 --- a/tests/project/test_getconfig.lua +++ b/tests/project/test_getconfig.lua @@ -29,7 +29,7 @@ -- function suite.usesCurrentOS_onNoSystemSpecified() - _OS = "linux" + _TARGET_OS = "linux" project ("MyProject") filter { "system:linux" } defines { "correct" } @@ -45,7 +45,7 @@ -- function suite.actionOverridesOS() - _OS = "linux" + _TARGET_OS = "linux" _ACTION = "vs2005" project ("MyProject") filter { "system:windows" } @@ -61,7 +61,7 @@ -- function suite.usesCfgSystem() - _OS = "linux" + _TARGET_OS = "linux" _ACTION = "vs2005" project ("MyProject") system "macosx" diff --git a/tests/tools/test_dotnet.lua b/tests/tools/test_dotnet.lua index 005d1a50..cd86946b 100644 --- a/tests/tools/test_dotnet.lua +++ b/tests/tools/test_dotnet.lua @@ -28,7 +28,7 @@ -- function suite.defaultCompiler_onWindows() - _OS = "windows" + _TARGET_OS = "windows" prepare() test.isequal("csc", dotnet.gettoolname(cfg, "csc")) end @@ -39,7 +39,7 @@ -- function suite.defaultCompiler_onMacOSX() - _OS = "macosx" + _TARGET_OS = "macosx" prepare() test.isequal("mcs", dotnet.gettoolname(cfg, "csc")) end From b3ad14a51c815e0203efd604226df98117f25024 Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Tue, 11 Apr 2017 14:41:07 -0700 Subject: [PATCH 44/59] current -> host. --- scripts/package.lua | 4 ++-- src/base/moduledownloader.lua | 2 +- src/base/os.lua | 14 +++++++------- src/host/{os_current.c => os_host.c} | 6 +++--- src/host/premake.c | 2 +- src/host/premake.h | 2 +- tests/base/test_os.lua | 12 ++++++------ 7 files changed, 21 insertions(+), 21 deletions(-) rename src/host/{os_current.c => os_host.c} (62%) diff --git a/scripts/package.lua b/scripts/package.lua index 4c4c1643..14251017 100644 --- a/scripts/package.lua +++ b/scripts/package.lua @@ -180,8 +180,8 @@ if kind == "binary" then os.chdir("bin/release") - local name = string.format("%s-%s%s", pkgName, os.current(), pkgExt) - if os.iscurrent("windows") then + local name = string.format("%s-%s%s", pkgName, os.host(), pkgExt) + if os.ishost("windows") then execQuiet("zip -9 %s premake5.exe", name) else execQuiet("tar czvf %s premake5", name) diff --git a/src/base/moduledownloader.lua b/src/base/moduledownloader.lua index 55b76950..339ee180 100644 --- a/src/base/moduledownloader.lua +++ b/src/base/moduledownloader.lua @@ -23,7 +23,7 @@ -- get current user. local user = 'UNKNOWN' - if os.iscurrent('windows') then + if os.ishost('windows') then user = os.getenv('USERNAME') or user else user = os.getenv('LOGNAME') or user diff --git a/src/base/os.lua b/src/base/os.lua index 82912481..ebb59b6a 100644 --- a/src/base/os.lua +++ b/src/base/os.lua @@ -143,7 +143,7 @@ end function os.get() - premake.warnOnce("os.get", "os.get() is deprecated, use 'os.target()' or 'os.current()'.") + premake.warnOnce("os.get", "os.get() is deprecated, use 'os.target()' or 'os.host()'.") return os.target() end @@ -180,17 +180,17 @@ end function os.is(id) - premake.warnOnce("os.is", "os.is() is deprecated, use 'os.istarget()' or 'os.iscurrent()'.") + premake.warnOnce("os.is", "os.is() is deprecated, use 'os.istarget()' or 'os.ishost()'.") return os.istarget(id) end -- --- Check the current executing operating system. +-- Check the current host operating system. -- - function os.iscurrent(id) - return (os.current():lower() == id:lower()) + function os.ishost(id) + return (os.host():lower() == id:lower()) end @@ -258,9 +258,9 @@ else -- Identify the system local arch - if os.iscurrent("windows") then + if os.ishost("windows") then arch = os.getenv("PROCESSOR_ARCHITECTURE") - elseif os.iscurrent("macosx") then + elseif os.ishost("macosx") then arch = os.outputof("echo $HOSTTYPE") else arch = os.outputof("uname -m") diff --git a/src/host/os_current.c b/src/host/os_host.c similarity index 62% rename from src/host/os_current.c rename to src/host/os_host.c index 9869e986..085a44c2 100644 --- a/src/host/os_current.c +++ b/src/host/os_host.c @@ -1,12 +1,12 @@ /** - * \file os_current.c - * \brief Get the current OS we're executing on. + * \file os_host.c + * \brief Get the current host OS we're executing on. * \author Copyright (c) 2014-2017 Tom van Dijck, Jason Perkins and the Premake project */ #include "premake.h" -int os_current(lua_State* L) +int os_host(lua_State* L) { lua_pushstring(L, PLATFORM_STRING); return 1; diff --git a/src/host/premake.c b/src/host/premake.c index 60cc2b0b..86449d4f 100644 --- a/src/host/premake.c +++ b/src/host/premake.c @@ -58,13 +58,13 @@ static const luaL_Reg os_functions[] = { { "chdir", os_chdir }, { "chmod", os_chmod }, { "copyfile", os_copyfile }, - { "current", os_current }, { "_is64bit", os_is64bit }, { "isdir", os_isdir }, { "getcwd", os_getcwd }, { "getpass", os_getpass }, { "getWindowsRegistry", os_getWindowsRegistry }, { "getversion", os_getversion }, + { "host", os_host }, { "isfile", os_isfile }, { "islink", os_islink }, { "locate", os_locate }, diff --git a/src/host/premake.h b/src/host/premake.h index 64f951ec..562d11a5 100644 --- a/src/host/premake.h +++ b/src/host/premake.h @@ -102,11 +102,11 @@ int path_wildcards(lua_State* L); int os_chdir(lua_State* L); int os_chmod(lua_State* L); int os_copyfile(lua_State* L); -int os_current(lua_State* L); int os_getcwd(lua_State* L); int os_getpass(lua_State* L); int os_getWindowsRegistry(lua_State* L); int os_getversion(lua_State* L); +int os_host(lua_State* L); int os_is64bit(lua_State* L); int os_isdir(lua_State* L); int os_isfile(lua_State* L); diff --git a/tests/base/test_os.lua b/tests/base/test_os.lua index 99931e29..f2414b95 100644 --- a/tests/base/test_os.lua +++ b/tests/base/test_os.lua @@ -232,41 +232,41 @@ -- os.getWindowsRegistry windows tests -- function suite.getreg_nonExistentValue() - if os.iscurrent("windows") then + if os.ishost("windows") then local x = os.getWindowsRegistry("HKCU:Should\\Not\\Exist\\At\\All") test.isequal(nil, x) end end function suite.getreg_nonExistentDefaultValue() - if os.iscurrent("windows") then + if os.ishost("windows") then local x = os.getWindowsRegistry("HKCU:Should\\Not\\Exist\\At\\All\\") test.isequal(nil, x) end end function suite.getreg_noSeparators() - if os.iscurrent("windows") then + if os.ishost("windows") then os.getWindowsRegistry("HKCU:ShouldNotExistAtAll") end end function suite.getreg_namedValue() - if os.iscurrent("windows") then + if os.ishost("windows") then local x = os.getWindowsRegistry("HKCU:Environment\\TEMP") test.istrue(x ~= nil) end end function suite.getreg_namedValueOptSeparator() - if os.iscurrent("windows") then + if os.ishost("windows") then local x = os.getWindowsRegistry("HKCU:\\Environment\\TEMP") test.istrue(x ~= nil) end end function suite.getreg_defaultValue() - if os.iscurrent("windows") then + if os.ishost("windows") then local x = os.getWindowsRegistry("HKLM:SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Minimal\\AppInfo\\") test.isequal("Service", x) end From 6d471ecc2a4e573e5859e4564612500dc3fd13d2 Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Mon, 24 Apr 2017 13:37:28 -0700 Subject: [PATCH 45/59] Add 'supports_language' callback to action to validate languages now that we have multiple dialects --- modules/codelite/_preload.lua | 5 ++++- modules/d/actions/gmake.lua | 4 +++- modules/d/actions/vstudio.lua | 4 +++- modules/raw/_preload.lua | 4 ---- modules/xcode/_preload.lua | 5 ++++- src/actions/make/_make.lua | 8 ++++++-- src/actions/vstudio/vs2005.lua | 6 +++++- src/actions/vstudio/vs2008.lua | 6 +++++- src/actions/vstudio/vs2010.lua | 6 +++++- src/actions/vstudio/vs2012.lua | 6 +++++- src/actions/vstudio/vs2013.lua | 6 +++++- src/actions/vstudio/vs2015.lua | 6 +++++- src/actions/vstudio/vs2017.lua | 6 +++++- src/base/action.lua | 23 ++++++++++++++--------- 14 files changed, 69 insertions(+), 26 deletions(-) diff --git a/modules/codelite/_preload.lua b/modules/codelite/_preload.lua index d7accaae..be544968 100644 --- a/modules/codelite/_preload.lua +++ b/modules/codelite/_preload.lua @@ -22,10 +22,13 @@ -- The capabilities of this action valid_kinds = { "ConsoleApp", "WindowedApp", "Makefile", "SharedLib", "StaticLib", "Utility" }, - valid_languages = { "C", "C++" }, valid_tools = { cc = { "gcc", "clang", "msc" } }, + supports_language = function(lang) + return p.languages.isc(lang) or + p.languages.iscpp(lang) + end, -- Workspace and project generation logic diff --git a/modules/d/actions/gmake.lua b/modules/d/actions/gmake.lua index 8559e8c4..6aa148e7 100644 --- a/modules/d/actions/gmake.lua +++ b/modules/d/actions/gmake.lua @@ -28,9 +28,11 @@ -- -- Patch the gmake action with the allowed tools... -- - gmake.valid_languages = table.join(gmake.valid_languages, { p.D } ) gmake.valid_tools.dc = { "dmd", "gdc", "ldc" } + p.override(gmake, "supports_language", function(oldfn, lang) + return oldfn(lang) or lang == p.D; + end) function m.make.separateCompilation(prj) local some = false diff --git a/modules/d/actions/vstudio.lua b/modules/d/actions/vstudio.lua index 31bef121..2106f29f 100644 --- a/modules/d/actions/vstudio.lua +++ b/modules/d/actions/vstudio.lua @@ -22,7 +22,9 @@ for k,v in pairs({ "vs2005", "vs2008", "vs2010", "vs2012", "vs2013", "vs2015" }) do local vs = p.action.get(v) if vs ~= nil then - table.insert( vs.valid_languages, p.D ) + p.override(vs, "supports_language", function(oldfn, lang) + return oldfn(lang) or lang == p.D; + end) vs.valid_tools.dc = { "dmd", "gdc", "ldc" } p.override(vs, "onProject", function(oldfn, prj) diff --git a/modules/raw/_preload.lua b/modules/raw/_preload.lua index b8bef93d..3c056a2e 100644 --- a/modules/raw/_preload.lua +++ b/modules/raw/_preload.lua @@ -4,10 +4,6 @@ newaction shortname = "Raw output", description = "Generate raw representation of Premake structures", - valid_kinds = { "ConsoleApp", "WindowedApp", "SharedLib", "StaticLib", "Makefile", "None", "Utility" }, - valid_languages = { "C", "C++" }, - valid_tools = { cc = { "clang" } }, - onsolution = function(sln) require('raw') diff --git a/modules/xcode/_preload.lua b/modules/xcode/_preload.lua index 4c1cc1b2..63b62bc8 100644 --- a/modules/xcode/_preload.lua +++ b/modules/xcode/_preload.lua @@ -40,10 +40,13 @@ -- The capabilities of this action valid_kinds = { "ConsoleApp", "WindowedApp", "SharedLib", "StaticLib", "Makefile", "None" }, - valid_languages = { "C", "C++" }, valid_tools = { cc = { "gcc", "clang" }, }, + supports_language = function(lang) + return p.languages.isc(lang) or + p.languages.iscpp(lang) + end, -- Workspace and project generation logic diff --git a/src/actions/make/_make.lua b/src/actions/make/_make.lua index 7da88ec9..dbd09b02 100644 --- a/src/actions/make/_make.lua +++ b/src/actions/make/_make.lua @@ -22,13 +22,17 @@ valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Utility", "Makefile" }, - valid_languages = { "C", "C++", "C#" }, - valid_tools = { cc = { "clang", "gcc" }, dotnet = { "mono", "msnet", "pnet" } }, + supports_language = function(lang) + return p.languages.isc(lang) or + p.languages.iscpp(lang) or + p.languages.isdotnet(lang) + end, + onWorkspace = function(wks) premake.escaper(make.esc) premake.generate(wks, make.getmakefilename(wks, false), make.generate_workspace) diff --git a/src/actions/vstudio/vs2005.lua b/src/actions/vstudio/vs2005.lua index 2a7ebc88..9cbfe81d 100644 --- a/src/actions/vstudio/vs2005.lua +++ b/src/actions/vstudio/vs2005.lua @@ -100,11 +100,15 @@ -- The capabilities of this action valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Makefile", "None" }, - valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, + supports_language = function(lang) + return p.languages.isc(lang) or + p.languages.iscpp(lang) or + p.languages.isdotnet(lang) + end, -- Workspace and project generation logic diff --git a/src/actions/vstudio/vs2008.lua b/src/actions/vstudio/vs2008.lua index afe3e49a..6ee1a6cf 100644 --- a/src/actions/vstudio/vs2008.lua +++ b/src/actions/vstudio/vs2008.lua @@ -27,11 +27,15 @@ -- The capabilities of this action valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Makefile", "None" }, - valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, + supports_language = function(lang) + return p.languages.isc(lang) or + p.languages.iscpp(lang) or + p.languages.isdotnet(lang) + end, -- Workspace and project generation logic diff --git a/src/actions/vstudio/vs2010.lua b/src/actions/vstudio/vs2010.lua index 4cd57f91..fd7109bb 100644 --- a/src/actions/vstudio/vs2010.lua +++ b/src/actions/vstudio/vs2010.lua @@ -123,11 +123,15 @@ -- The capabilities of this action valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Makefile", "None", "Utility" }, - valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, + supports_language = function(lang) + return p.languages.isc(lang) or + p.languages.iscpp(lang) or + p.languages.isdotnet(lang) + end, -- Workspace and project generation logic diff --git a/src/actions/vstudio/vs2012.lua b/src/actions/vstudio/vs2012.lua index 4f46dc56..cc6910b6 100644 --- a/src/actions/vstudio/vs2012.lua +++ b/src/actions/vstudio/vs2012.lua @@ -29,11 +29,15 @@ -- The capabilities of this action valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Makefile", "None", "Utility" }, - valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, + supports_language = function(lang) + return p.languages.isc(lang) or + p.languages.iscpp(lang) or + p.languages.isdotnet(lang) + end, -- Workspace and project generation logic diff --git a/src/actions/vstudio/vs2013.lua b/src/actions/vstudio/vs2013.lua index 558f02bc..7ade06db 100644 --- a/src/actions/vstudio/vs2013.lua +++ b/src/actions/vstudio/vs2013.lua @@ -31,11 +31,15 @@ -- The capabilities of this action valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Makefile", "None", "Utility" }, - valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, + supports_language = function(lang) + return p.languages.isc(lang) or + p.languages.iscpp(lang) or + p.languages.isdotnet(lang) + end, -- Workspace and project generation logic diff --git a/src/actions/vstudio/vs2015.lua b/src/actions/vstudio/vs2015.lua index 88ab8e5e..ab2676a3 100644 --- a/src/actions/vstudio/vs2015.lua +++ b/src/actions/vstudio/vs2015.lua @@ -31,11 +31,15 @@ -- The capabilities of this action valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Makefile", "None", "Utility" }, - valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, + supports_language = function(lang) + return p.languages.isc(lang) or + p.languages.iscpp(lang) or + p.languages.isdotnet(lang) + end, -- Workspace and project generation logic diff --git a/src/actions/vstudio/vs2017.lua b/src/actions/vstudio/vs2017.lua index 0d5617c3..0ecb53f9 100644 --- a/src/actions/vstudio/vs2017.lua +++ b/src/actions/vstudio/vs2017.lua @@ -31,11 +31,15 @@ -- The capabilities of this action valid_kinds = { "ConsoleApp", "WindowedApp", "StaticLib", "SharedLib", "Makefile", "None", "Utility", "Installer" }, - valid_languages = { "C", "C++", "C#" }, valid_tools = { cc = { "msc" }, dotnet = { "msnet" }, }, + supports_language = function(lang) + return p.languages.isc(lang) or + p.languages.iscpp(lang) or + p.languages.isdotnet(lang) + end, -- Workspace and project generation logic diff --git a/src/base/action.lua b/src/base/action.lua index c403742c..5edabf23 100644 --- a/src/base/action.lua +++ b/src/base/action.lua @@ -239,19 +239,24 @@ if not self then return false end - if not self.valid_languages and not self.valid_kinds then + + if not self.valid_languages and not self.valid_kinds and not self.supports_language then return true end - if self.valid_languages then - if table.contains(self.valid_languages, feature) then - return true - end + + if self.valid_languages and table.contains(self.valid_languages, feature) then + return true end - if self.valid_kinds then - if table.contains(self.valid_kinds, feature) then - return true - end + + if self.valid_kinds and table.contains(self.valid_kinds, feature) then + return true end + + if self.supports_language and self.supports_language(feature) then + return true + end + + return false end From 8827098d30b2a185b54fb6d05bc2536dc4d3018e Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Mon, 24 Apr 2017 13:53:49 -0700 Subject: [PATCH 46/59] Fix a call to deprecated os.get() --- src/host/path_translate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/host/path_translate.c b/src/host/path_translate.c index ef06665a..0c0f4eae 100644 --- a/src/host/path_translate.c +++ b/src/host/path_translate.c @@ -35,7 +35,7 @@ int path_translate(lua_State* L) if (lua_gettop(L) == 1) { // Get target OS lua_getglobal(L, "os"); - lua_getfield(L, -1, "get"); + lua_getfield(L, -1, "target"); lua_call(L, 0, 1); os = luaL_checkstring(L, -1); lua_pop(L, 2); From fa3328440e2ecf111e4c5387e7fba68d58935140 Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Tue, 25 Apr 2017 15:44:13 +1000 Subject: [PATCH 47/59] Increased consistency of p. usage --- modules/codelite/codelite_project.lua | 6 +-- .../codelite/tests/test_codelite_config.lua | 7 +-- .../codelite/tests/test_codelite_project.lua | 9 ++-- .../tests/test_codelite_workspace.lua | 7 +-- modules/d/d.lua | 2 +- modules/d/tests/test_dmd.lua | 15 ++++--- modules/d/tests/test_gdc.lua | 15 ++++--- modules/d/tests/test_gmake.lua | 17 +++---- modules/d/tests/test_ldc.lua | 15 ++++--- modules/d/tests/test_visualstudio.lua | 13 +++--- modules/d/tools/dmd.lua | 31 ++++++------- modules/d/tools/gdc.lua | 27 +++++------ modules/d/tools/ldc.lua | 23 +++++----- modules/raw/raw_action.lua | 5 ++- modules/self-test/test_assertions.lua | 8 ++-- modules/xcode/tests/test_header_footer.lua | 3 +- modules/xcode/tests/test_xcode4_project.lua | 7 +-- modules/xcode/tests/test_xcode4_workspace.lua | 3 +- .../xcode/tests/test_xcode_dependencies.lua | 7 +-- modules/xcode/tests/test_xcode_project.lua | 17 +++---- modules/xcode/xcode4_workspace.lua | 2 +- modules/xcode/xcode_common.lua | 16 +++---- modules/xcode/xcode_project.lua | 2 +- src/_premake_main.lua | 24 +++++----- src/actions/make/_make.lua | 32 ++++++------- src/actions/make/make_cpp.lua | 24 +++++----- src/actions/make/make_csharp.lua | 45 ++++++++++--------- src/actions/make/make_makefile.lua | 10 ++--- src/actions/make/make_utility.lua | 10 ++--- src/actions/make/make_workspace.lua | 8 ++-- src/actions/vstudio/_vstudio.lua | 16 +++---- src/actions/vstudio/vs2005.lua | 12 ++--- src/actions/vstudio/vs2005_csproj.lua | 24 +++++----- src/actions/vstudio/vs2005_solution.lua | 14 +++--- src/actions/vstudio/vs2008.lua | 7 +-- src/actions/vstudio/vs200x_vcproj.lua | 8 ++-- src/actions/vstudio/vs2010.lua | 6 +-- src/actions/vstudio/vs2010_nuget.lua | 6 +-- src/actions/vstudio/vs2010_rules_props.lua | 10 ++--- src/actions/vstudio/vs2010_rules_targets.lua | 9 ++-- src/actions/vstudio/vs2010_rules_xml.lua | 9 ++-- src/actions/vstudio/vs2010_vcxproj.lua | 6 +-- .../vstudio/vs2010_vcxproj_filters.lua | 2 +- src/actions/vstudio/vs2010_vcxproj_user.lua | 2 +- src/actions/vstudio/vs2012.lua | 5 +-- src/actions/vstudio/vs2013.lua | 4 +- src/actions/vstudio/vs2015.lua | 4 +- src/actions/vstudio/vs2017.lua | 4 +- src/base/action.lua | 6 +-- src/base/api.lua | 32 ++++++------- src/base/config.lua | 6 +-- src/base/detoken.lua | 4 +- src/base/field.lua | 9 ++-- src/base/fileconfig.lua | 6 +-- src/base/languages.lua | 6 +-- src/base/option.lua | 15 ++++--- src/base/oven.lua | 4 +- src/base/premake.lua | 32 ++++++------- src/base/tools.lua | 2 +- src/base/tree.lua | 5 ++- src/base/validation.lua | 5 +-- src/tools/clang.lua | 21 ++++----- src/tools/dotnet.lua | 11 ++--- src/tools/gcc.lua | 42 ++++++++--------- src/tools/msc.lua | 6 +-- tests/actions/make/cpp/test_clang.lua | 9 ++-- tests/actions/make/cpp/test_file_rules.lua | 9 ++-- tests/actions/make/cpp/test_flags.lua | 9 ++-- tests/actions/make/cpp/test_ldflags.lua | 17 +++---- tests/actions/make/cpp/test_make_linking.lua | 9 ++-- tests/actions/make/cpp/test_make_pch.lua | 5 ++- tests/actions/make/cpp/test_target_rules.lua | 5 ++- tests/actions/make/cpp/test_tools.lua | 9 ++-- tests/actions/make/cpp/test_wiidev.lua | 11 ++--- tests/actions/make/cs/test_embed_files.lua | 11 ++--- tests/actions/make/cs/test_flags.lua | 9 ++-- tests/actions/make/cs/test_links.lua | 9 ++-- tests/actions/make/cs/test_response.lua | 5 ++- tests/actions/make/cs/test_sources.lua | 11 ++--- tests/actions/make/test_make_escaping.lua | 3 +- tests/actions/make/test_make_tovar.lua | 3 +- .../make/workspace/test_config_maps.lua | 3 +- .../make/workspace/test_group_rule.lua | 3 +- .../actions/make/workspace/test_help_rule.lua | 3 +- .../make/workspace/test_project_rule.lua | 5 ++- .../actions/vstudio/cs2005/projectelement.lua | 13 +++--- .../vstudio/cs2005/projectsettings.lua | 14 +++--- .../vstudio/cs2005/test_assembly_refs.lua | 6 +-- .../vstudio/cs2005/test_build_events.lua | 7 +-- .../vstudio/cs2005/test_common_props.lua | 5 ++- .../vstudio/cs2005/test_compiler_props.lua | 7 +-- .../vstudio/cs2005/test_debug_props.lua | 7 +-- tests/actions/vstudio/cs2005/test_files.lua | 5 ++- tests/actions/vstudio/cs2005/test_icon.lua | 3 +- .../vstudio/cs2005/test_nuget_config.lua | 7 +-- .../cs2005/test_nuget_packages_config.lua | 7 +-- .../vstudio/cs2005/test_output_props.lua | 11 ++--- .../vstudio/cs2005/test_platform_groups.lua | 13 +++--- .../vstudio/cs2005/test_project_refs.lua | 5 ++- tests/actions/vstudio/cs2005/test_targets.lua | 5 ++- .../actions/vstudio/cs2005/test_user_file.lua | 5 ++- .../vstudio/sln2005/test_dependencies.lua | 9 ++-- tests/actions/vstudio/sln2005/test_header.lua | 13 +++--- .../vstudio/sln2005/test_nested_projects.lua | 6 +-- .../vstudio/sln2005/test_platforms.lua | 5 ++- .../actions/vstudio/sln2005/test_projects.lua | 7 +-- .../actions/vstudio/sln2005/test_sections.lua | 7 +-- .../vstudio/vc200x/test_assembly_refs.lua | 5 ++- .../vstudio/vc200x/test_build_steps.lua | 5 ++- .../vstudio/vc200x/test_compiler_block.lua | 11 ++--- .../vstudio/vc200x/test_configuration.lua | 9 ++-- .../vstudio/vc200x/test_debug_settings.lua | 9 ++-- .../vstudio/vc200x/test_excluded_configs.lua | 7 +-- tests/actions/vstudio/vc200x/test_files.lua | 7 +-- .../vstudio/vc200x/test_linker_block.lua | 7 +-- .../vstudio/vc200x/test_manifest_block.lua | 5 ++- .../vstudio/vc200x/test_nmake_settings.lua | 5 ++- .../actions/vstudio/vc200x/test_platforms.lua | 5 ++- tests/actions/vstudio/vc200x/test_project.lua | 3 +- .../vstudio/vc200x/test_project_refs.lua | 5 ++- .../vstudio/vc200x/test_resource_compiler.lua | 5 ++- .../actions/vstudio/vc200x/test_user_file.lua | 5 ++- .../vstudio/vc2010/test_assembly_refs.lua | 5 ++- .../vstudio/vc2010/test_build_events.lua | 5 ++- .../actions/vstudio/vc2010/test_build_log.lua | 5 ++- .../vstudio/vc2010/test_character_set.lua | 3 +- .../vstudio/vc2010/test_compile_settings.lua | 15 ++++--- .../vstudio/vc2010/test_config_props.lua | 7 +-- .../vstudio/vc2010/test_debug_settings.lua | 7 +-- .../vc2010/test_ensure_nuget_imports.lua | 9 ++-- .../vstudio/vc2010/test_excluded_configs.lua | 5 ++- .../vc2010/test_extension_settings.lua | 7 +-- .../vstudio/vc2010/test_extension_targets.lua | 7 +-- tests/actions/vstudio/vc2010/test_files.lua | 5 ++- .../vstudio/vc2010/test_filter_ids.lua | 5 ++- tests/actions/vstudio/vc2010/test_filters.lua | 5 ++- .../vstudio/vc2010/test_floatingpoint.lua | 5 ++- tests/actions/vstudio/vc2010/test_globals.lua | 9 ++-- tests/actions/vstudio/vc2010/test_header.lua | 9 ++-- .../vstudio/vc2010/test_imagexex_settings.lua | 5 ++- .../vstudio/vc2010/test_item_def_group.lua | 5 ++- .../vstudio/vc2010/test_language_settings.lua | 7 +-- .../vstudio/vc2010/test_language_targets.lua | 7 +-- tests/actions/vstudio/vc2010/test_link.lua | 21 ++++----- .../actions/vstudio/vc2010/test_manifest.lua | 7 +-- .../vstudio/vc2010/test_nmake_props.lua | 9 ++-- .../vc2010/test_nuget_packages_config.lua | 11 ++--- .../vstudio/vc2010/test_output_props.lua | 5 ++- .../vstudio/vc2010/test_platform_toolset.lua | 11 ++--- .../vstudio/vc2010/test_project_configs.lua | 5 ++- .../vstudio/vc2010/test_project_refs.lua | 5 ++- .../vstudio/vc2010/test_prop_sheet.lua | 7 +-- .../vstudio/vc2010/test_resource_compile.lua | 9 ++-- .../vstudio/vc2010/test_rule_props.lua | 8 ++-- .../vstudio/vc2010/test_rule_targets.lua | 8 ++-- .../actions/vstudio/vc2010/test_rule_vars.lua | 6 +-- .../actions/vstudio/vc2010/test_rule_xml.lua | 8 ++-- .../vstudio/vc2010/test_target_machine.lua | 3 +- .../actions/vstudio/vc2010/test_user_file.lua | 5 ++- .../vstudio/vc2010/test_vectorextensions.lua | 13 +++--- tests/api/test_boolean_kind.lua | 3 +- tests/api/test_containers.lua | 5 ++- tests/api/test_deprecations.lua | 3 +- tests/api/test_directory_kind.lua | 3 +- tests/api/test_list_kind.lua | 3 +- tests/api/test_path_kind.lua | 3 +- tests/api/test_register.lua | 5 ++- tests/api/test_string_kind.lua | 3 +- tests/api/test_table_kind.lua | 3 +- tests/base/test_configset.lua | 6 +-- tests/base/test_context.lua | 8 ++-- tests/base/test_criteria.lua | 8 ++-- tests/base/test_detoken.lua | 6 +-- tests/base/test_include.lua | 15 ++++--- tests/base/test_module_loader.lua | 3 +- tests/base/test_option.lua | 3 +- tests/base/test_override.lua | 11 ++--- tests/base/test_tree.lua | 3 +- tests/config/test_linkinfo.lua | 5 ++- tests/config/test_links.lua | 5 ++- tests/config/test_targetinfo.lua | 5 ++- tests/oven/test_filtering.lua | 5 ++- tests/oven/test_objdirs.lua | 3 +- tests/project/test_eachconfig.lua | 3 +- tests/project/test_sources.lua | 5 ++- tests/project/test_vpaths.lua | 3 +- tests/tools/test_dotnet.lua | 3 +- tests/tools/test_gcc.lua | 5 ++- tests/tools/test_msc.lua | 3 +- tests/tools/test_snc.lua | 3 +- tests/workspace/test_objdirs.lua | 5 ++- 191 files changed, 868 insertions(+), 735 deletions(-) diff --git a/modules/codelite/codelite_project.lua b/modules/codelite/codelite_project.lua index b842e8a4..102ca1ee 100755 --- a/modules/codelite/codelite_project.lua +++ b/modules/codelite/codelite_project.lua @@ -281,17 +281,17 @@ _p(3, '', iif(cfg.debugremotehost, "yes", "no"), cfg.debugremotehost or "", iif(cfg.debugport, tostring(cfg.debugport), ""), iif(cfg.debugextendedprotocol, "yes", "no")) if #cfg.debugsearchpaths > 0 then - _p(4, '%s', table.concat(premake.esc(project.getrelative(cfg.project, cfg.debugsearchpaths)), "\n")) + _p(4, '%s', table.concat(p.esc(project.getrelative(cfg.project, cfg.debugsearchpaths)), "\n")) else _p(4, '') end if #cfg.debugconnectcommands > 0 then - _p(4, '%s', table.concat(premake.esc(cfg.debugconnectcommands), "\n")) + _p(4, '%s', table.concat(p.esc(cfg.debugconnectcommands), "\n")) else _p(4, '') end if #cfg.debugstartupcommands > 0 then - _p(4, '%s', table.concat(premake.esc(cfg.debugstartupcommands), "\n")) + _p(4, '%s', table.concat(p.esc(cfg.debugstartupcommands), "\n")) else _p(4, '') end diff --git a/modules/codelite/tests/test_codelite_config.lua b/modules/codelite/tests/test_codelite_config.lua index f17f9a78..0719d771 100644 --- a/modules/codelite/tests/test_codelite_config.lua +++ b/modules/codelite/tests/test_codelite_config.lua @@ -6,7 +6,8 @@ local suite = test.declare("codelite_cproj_config") - local codelite = premake.modules.codelite + local p = premake + local codelite = p.modules.codelite --------------------------------------------------------------------------- -- Setup/Teardown @@ -15,8 +16,8 @@ local wks, prj, cfg function suite.setup() - premake.action.set("codelite") - premake.indent(" ") + p.action.set("codelite") + p.indent(" ") wks, prj = test.createWorkspace() end diff --git a/modules/codelite/tests/test_codelite_project.lua b/modules/codelite/tests/test_codelite_project.lua index 631ab7e1..ff72ebb5 100644 --- a/modules/codelite/tests/test_codelite_project.lua +++ b/modules/codelite/tests/test_codelite_project.lua @@ -6,7 +6,8 @@ local suite = test.declare("codelite_cproj") - local codelite = premake.modules.codelite + local p = premake + local codelite = p.modules.codelite --------------------------------------------------------------------------- -- Setup/Teardown @@ -15,13 +16,13 @@ local wks, prj function suite.setup() - premake.action.set("codelite") - premake.indent(" ") + p.action.set("codelite") + p.indent(" ") wks = test.createWorkspace() end local function prepare() - wks = premake.oven.bakeWorkspace(wks) + wks = p.oven.bakeWorkspace(wks) prj = test.getproject(wks, 1) end diff --git a/modules/codelite/tests/test_codelite_workspace.lua b/modules/codelite/tests/test_codelite_workspace.lua index f63453bf..cd56fd07 100644 --- a/modules/codelite/tests/test_codelite_workspace.lua +++ b/modules/codelite/tests/test_codelite_workspace.lua @@ -6,7 +6,8 @@ --- local suite = test.declare("codelite_workspace") - local codelite = premake.modules.codelite + local p = premake + local codelite = p.modules.codelite -- @@ -16,8 +17,8 @@ local wks, prj function suite.setup() - premake.action.set("codelite") - premake.indent(" ") + p.action.set("codelite") + p.indent(" ") wks = test.createWorkspace() end diff --git a/modules/d/d.lua b/modules/d/d.lua index cc7908bb..45c2152d 100644 --- a/modules/d/d.lua +++ b/modules/d/d.lua @@ -20,7 +20,7 @@ -- Patch the project table to provide knowledge of D projects -- function p.project.isd(prj) - return prj.language == premake.D + return prj.language == p.D end -- diff --git a/modules/d/tests/test_dmd.lua b/modules/d/tests/test_dmd.lua index a12f5bc6..98f5205d 100644 --- a/modules/d/tests/test_dmd.lua +++ b/modules/d/tests/test_dmd.lua @@ -5,10 +5,11 @@ --- local suite = test.declare("d_dmd") - local m = premake.modules.d + local p = premake + local m = p.modules.d - local make = premake.make - local project = premake.project + local make = p.make + local project = p.project --------------------------------------------------------------------------- @@ -18,15 +19,15 @@ local wks, prj, cfg function suite.setup() - premake.escaper(make.esc) + p.escaper(make.esc) wks = test.createWorkspace() end local function prepare_cfg(calls) - prj = premake.workspace.getproject(wks, 1) + prj = p.workspace.getproject(wks, 1) local cfg = test.getconfig(prj, "Debug") - local toolset = premake.tools.dmd - premake.callArray(calls, cfg, toolset) + local toolset = p.tools.dmd + p.callArray(calls, cfg, toolset) end diff --git a/modules/d/tests/test_gdc.lua b/modules/d/tests/test_gdc.lua index a22ba25c..c0e9c670 100644 --- a/modules/d/tests/test_gdc.lua +++ b/modules/d/tests/test_gdc.lua @@ -5,10 +5,11 @@ --- local suite = test.declare("d_gdc") - local m = premake.modules.d + local p = premake + local m = p.modules.d - local make = premake.make - local project = premake.project + local make = p.make + local project = p.project --------------------------------------------------------------------------- @@ -18,15 +19,15 @@ local wks, prj, cfg function suite.setup() - premake.escaper(make.esc) + p.escaper(make.esc) wks = test.createWorkspace() end local function prepare_cfg(calls) - prj = premake.workspace.getproject(wks, 1) + prj = p.workspace.getproject(wks, 1) local cfg = test.getconfig(prj, "Debug") - local toolset = premake.tools.gdc - premake.callArray(calls, cfg, toolset) + local toolset = p.tools.gdc + p.callArray(calls, cfg, toolset) end diff --git a/modules/d/tests/test_gmake.lua b/modules/d/tests/test_gmake.lua index af70043d..73b69162 100644 --- a/modules/d/tests/test_gmake.lua +++ b/modules/d/tests/test_gmake.lua @@ -5,10 +5,11 @@ --- local suite = test.declare("d_make") - local m = premake.modules.d + local p = premake + local m = p.modules.d - local make = premake.make - local project = premake.project + local make = p.make + local project = p.project --------------------------------------------------------------------------- @@ -18,19 +19,19 @@ local wks, prj, cfg function suite.setup() - premake.escaper(make.esc) + p.escaper(make.esc) wks = test.createWorkspace() end local function prepare() - prj = premake.workspace.getproject(wks, 1) + prj = p.workspace.getproject(wks, 1) end local function prepare_cfg(calls) - prj = premake.workspace.getproject(wks, 1) + prj = p.workspace.getproject(wks, 1) local cfg = test.getconfig(prj, "Debug") - local toolset = premake.tools.dmd - premake.callArray(calls, cfg, toolset) + local toolset = p.tools.dmd + p.callArray(calls, cfg, toolset) end diff --git a/modules/d/tests/test_ldc.lua b/modules/d/tests/test_ldc.lua index 94cd13aa..358883c6 100644 --- a/modules/d/tests/test_ldc.lua +++ b/modules/d/tests/test_ldc.lua @@ -5,10 +5,11 @@ --- local suite = test.declare("d_ldc") - local m = premake.modules.d + local p = premake + local m = p.modules.d - local make = premake.make - local project = premake.project + local make = p.make + local project = p.project --------------------------------------------------------------------------- @@ -18,15 +19,15 @@ local wks, prj, cfg function suite.setup() - premake.escaper(make.esc) + p.escaper(make.esc) wks = test.createWorkspace() end local function prepare_cfg(calls) - prj = premake.workspace.getproject(wks, 1) + prj = p.workspace.getproject(wks, 1) local cfg = test.getconfig(prj, "Debug") - local toolset = premake.tools.ldc - premake.callArray(calls, cfg, toolset) + local toolset = p.tools.ldc + p.callArray(calls, cfg, toolset) end diff --git a/modules/d/tests/test_visualstudio.lua b/modules/d/tests/test_visualstudio.lua index c0bc19de..da6a53fe 100644 --- a/modules/d/tests/test_visualstudio.lua +++ b/modules/d/tests/test_visualstudio.lua @@ -5,7 +5,8 @@ --- local suite = test.declare("visual_d") - local m = premake.modules.d + local p = premake + local m = p.modules.d --------------------------------------------------------------------------- @@ -15,9 +16,9 @@ local wks, prj, cfg function suite.setup() - premake.action.set("vs2010") --- premake.escaper(premake.vstudio.vs2005.esc) - premake.indent(" ") + p.action.set("vs2010") +-- p.escaper(p.vstudio.vs2005.esc) + p.indent(" ") wks = workspace "MyWorkspace" configurations { "Debug", "Release" } language "D" @@ -41,8 +42,8 @@ function suite.slnProj() project "MyProject" language "D" - premake.vstudio.sln2005.reorderProjects(wks) - premake.vstudio.sln2005.projects(wks) + p.vstudio.sln2005.reorderProjects(wks) + p.vstudio.sln2005.projects(wks) test.capture [[ Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "MyProject", "MyProject.visualdproj", "{42B5DBC6-AE1F-903D-F75D-41E363076E92}" EndProject diff --git a/modules/d/tools/dmd.lua b/modules/d/tools/dmd.lua index fc0796d8..59161946 100644 --- a/modules/d/tools/dmd.lua +++ b/modules/d/tools/dmd.lua @@ -6,9 +6,10 @@ local tdmd = {} - local project = premake.project - local config = premake.config - local d = premake.modules.d + local p = premake + local project = p.project + local config = p.config + local d = p.modules.d -- -- Set default tools @@ -83,7 +84,7 @@ -- skip external project references, since I have no way -- to know the actual output target path if not link.project.external then - if link.kind == premake.STATICLIB then + if link.kind == p.STATICLIB then -- Don't use "-l" flag when linking static libraries; instead use -- path/libname.a to avoid linking a shared library of the same -- name if one is present @@ -166,7 +167,7 @@ -- to know the actual output target path if not link.project.externalname then local linkinfo = config.getlinkinfo(link) - if link.kind == premake.STATICLIB then + if link.kind == p.STATICLIB then table.insert(result, project.getrelative(cfg.project, linkinfo.abspath)) end end @@ -177,7 +178,7 @@ for _, link in ipairs(links) do if path.isobjectfile(link) then table.insert(result, link) - elseif path.hasextension(link, premake.systems[cfg.system].staticlib.extension) then + elseif path.hasextension(link, p.systems[cfg.system].staticlib.extension) then table.insert(result, link) end end @@ -192,17 +193,17 @@ -- ///////////////////////////////////////////////////////////////////////// -- if we are compiling on windows, we need to specialise to OPTLINK as the linker --- OR!!! if cfg.system ~= premake.WINDOWS then +-- OR!!! if cfg.system ~= p.WINDOWS then if string.match( os.getversion().description, "Windows" ) ~= nil then -- TODO: on windows, we may use OPTLINK or MSLINK (for Win64)... -- printf("TODO: select proper linker for 32/64 bit code") - premake.tools.dmd = tdmd.optlink + p.tools.dmd = tdmd.optlink else - premake.tools.dmd = tdmd.gcc + p.tools.dmd = tdmd.gcc end - local dmd = premake.tools.dmd + local dmd = p.tools.dmd -- @@ -265,18 +266,18 @@ if cfg.flags.Documentation then if cfg.docname then - table.insert(flags, "-Df" .. premake.quoted(cfg.docname)) + table.insert(flags, "-Df" .. p.quoted(cfg.docname)) end if cfg.docdir then - table.insert(flags, "-Dd" .. premake.quoted(cfg.docdir)) + table.insert(flags, "-Dd" .. p.quoted(cfg.docdir)) end end if cfg.flags.GenerateHeader then if cfg.headername then - table.insert(flags, "-Hf" .. premake.quoted(cfg.headername)) + table.insert(flags, "-Hf" .. p.quoted(cfg.headername)) end if cfg.headerdir then - table.insert(flags, "-Hd" .. premake.quoted(cfg.headerdir)) + table.insert(flags, "-Hd" .. p.quoted(cfg.headerdir)) end end @@ -324,7 +325,7 @@ local result = {} for _, dir in ipairs(dirs) do dir = project.getrelative(cfg.project, dir) - table.insert(result, '-I' .. premake.quoted(dir)) + table.insert(result, '-I' .. p.quoted(dir)) end return result end diff --git a/modules/d/tools/gdc.lua b/modules/d/tools/gdc.lua index d8e42558..21dc08c3 100644 --- a/modules/d/tools/gdc.lua +++ b/modules/d/tools/gdc.lua @@ -4,12 +4,13 @@ -- Copyright (c) 2013-2015 Andrew Gough, Manu Evans, and the Premake project -- - premake.tools.gdc = { } + local p = premake + p.tools.gdc = { } - local gdc = premake.tools.gdc - local project = premake.project - local config = premake.config - local d = premake.modules.d + local gdc = p.tools.gdc + local project = p.project + local config = p.config + local d = p.modules.d -- -- Set default tools @@ -83,18 +84,18 @@ if cfg.flags.Documentation then if cfg.docname then - table.insert(flags, "-fdoc-file=" .. premake.quoted(cfg.docname)) + table.insert(flags, "-fdoc-file=" .. p.quoted(cfg.docname)) end if cfg.docdir then - table.insert(flags, "-fdoc-dir=" .. premake.quoted(cfg.docdir)) + table.insert(flags, "-fdoc-dir=" .. p.quoted(cfg.docdir)) end end if cfg.flags.GenerateHeader then if cfg.headername then - table.insert(flags, "-fintfc-file=" .. premake.quoted(cfg.headername)) + table.insert(flags, "-fintfc-file=" .. p.quoted(cfg.headername)) end if cfg.headerdir then - table.insert(flags, "-fintfc-dir=" .. premake.quoted(cfg.headerdir)) + table.insert(flags, "-fintfc-dir=" .. p.quoted(cfg.headerdir)) end end @@ -142,7 +143,7 @@ local result = {} for _, dir in ipairs(dirs) do dir = project.getrelative(cfg.project, dir) - table.insert(result, '-I' .. premake.quoted(dir)) + table.insert(result, '-I' .. p.quoted(dir)) end return result end @@ -168,14 +169,14 @@ }, kind = { SharedLib = function(cfg) - local r = { iif(cfg.system == premake.MACOSX, "-dynamiclib", "-shared") } + local r = { iif(cfg.system == p.MACOSX, "-dynamiclib", "-shared") } if cfg.system == "windows" and not cfg.flags.NoImportLib then table.insert(r, '-Wl,--out-implib="' .. cfg.linktarget.relpath .. '"') end return r end, WindowedApp = function(cfg) - if cfg.system == premake.WINDOWS then return "-mwindows" end + if cfg.system == p.WINDOWS then return "-mwindows" end end, }, } @@ -224,7 +225,7 @@ -- skip external project references, since I have no way -- to know the actual output target path if not link.project.external then - if link.kind == premake.STATICLIB then + if link.kind == p.STATICLIB then -- Don't use "-l" flag when linking static libraries; instead use -- path/libname.a to avoid linking a shared library of the same -- name if one is present diff --git a/modules/d/tools/ldc.lua b/modules/d/tools/ldc.lua index 6c79840a..4d461885 100644 --- a/modules/d/tools/ldc.lua +++ b/modules/d/tools/ldc.lua @@ -4,12 +4,13 @@ -- Copyright (c) 2013-2015 Andrew Gough, Manu Evans, and the Premake project -- - premake.tools.ldc = { } + local p = premake + p.tools.ldc = { } - local ldc = premake.tools.ldc - local project = premake.project - local config = premake.config - local d = premake.modules.d + local ldc = p.tools.ldc + local project = p.project + local config = p.config + local d = p.modules.d -- @@ -89,18 +90,18 @@ if cfg.flags.Documentation then if cfg.docname then - table.insert(flags, "-Df=" .. premake.quoted(cfg.docname)) + table.insert(flags, "-Df=" .. p.quoted(cfg.docname)) end if cfg.docdir then - table.insert(flags, "-Dd=" .. premake.quoted(cfg.docdir)) + table.insert(flags, "-Dd=" .. p.quoted(cfg.docdir)) end end if cfg.flags.GenerateHeader then if cfg.headername then - table.insert(flags, "-Hf=" .. premake.quoted(cfg.headername)) + table.insert(flags, "-Hf=" .. p.quoted(cfg.headername)) end if cfg.headerdir then - table.insert(flags, "-Hd=" .. premake.quoted(cfg.headerdir)) + table.insert(flags, "-Hd=" .. p.quoted(cfg.headerdir)) end end @@ -148,7 +149,7 @@ local result = {} for _, dir in ipairs(dirs) do dir = project.getrelative(cfg.project, dir) - table.insert(result, '-I=' .. premake.quoted(dir)) + table.insert(result, '-I=' .. p.quoted(dir)) end return result end @@ -222,7 +223,7 @@ -- skip external project references, since I have no way -- to know the actual output target path if not link.project.external then - if link.kind == premake.STATICLIB then + if link.kind == p.STATICLIB then -- Don't use "-l" flag when linking static libraries; instead use -- path/libname.a to avoid linking a shared library of the same -- name if one is present diff --git a/modules/raw/raw_action.lua b/modules/raw/raw_action.lua index 2d06fdf0..f2539105 100644 --- a/modules/raw/raw_action.lua +++ b/modules/raw/raw_action.lua @@ -1,5 +1,6 @@ -premake.raw = { } -local raw = premake.raw +local p = premake +p.raw = { } +local raw = p.raw local gvisited = { } function raw.solution(sln) diff --git a/modules/self-test/test_assertions.lua b/modules/self-test/test_assertions.lua index 16d3e574..32f97d56 100644 --- a/modules/self-test/test_assertions.lua +++ b/modules/self-test/test_assertions.lua @@ -16,10 +16,10 @@ function m.capture(expected) - local actual = premake.captured() .. premake.eol() + local actual = p.captured() .. p.eol() -- create line-by-line iterators for both values - local ait = actual:gmatch("(.-)" .. premake.eol()) + local ait = actual:gmatch("(.-)" .. p.eol()) local eit = expected:gmatch("(.-)\n") -- compare each value line by line @@ -109,7 +109,7 @@ function m.hasoutput() - local actual = premake.captured() + local actual = p.captured() if actual == "" then m.fail("expected output, received none"); end @@ -118,7 +118,7 @@ function m.isemptycapture() - local actual = premake.captured() + local actual = p.captured() if actual ~= "" then m.fail("expected empty capture, but was %s", actual); end diff --git a/modules/xcode/tests/test_header_footer.lua b/modules/xcode/tests/test_header_footer.lua index dadac52d..9f140c24 100644 --- a/modules/xcode/tests/test_header_footer.lua +++ b/modules/xcode/tests/test_header_footer.lua @@ -6,7 +6,8 @@ --- local suite = test.declare("xcode_header") - local xcode = premake.modules.xcode + local p = premake + local xcode = p.modules.xcode -- diff --git a/modules/xcode/tests/test_xcode4_project.lua b/modules/xcode/tests/test_xcode4_project.lua index bf4b3961..8507547b 100644 --- a/modules/xcode/tests/test_xcode4_project.lua +++ b/modules/xcode/tests/test_xcode4_project.lua @@ -6,7 +6,8 @@ local suite = test.declare("xcode4_proj") - local xcode = premake.modules.xcode + local p = premake + local xcode = p.modules.xcode -- @@ -56,9 +57,9 @@ end local function prepare() - wks = premake.oven.bakeWorkspace(wks) + wks = p.oven.bakeWorkspace(wks) xcode.prepareWorkspace(wks) - local prj = premake.workspace.getproject(wks, 1) + local prj = p.workspace.getproject(wks, 1) tr = xcode.buildprjtree(prj) end diff --git a/modules/xcode/tests/test_xcode4_workspace.lua b/modules/xcode/tests/test_xcode4_workspace.lua index d0f25abf..e4427ed4 100644 --- a/modules/xcode/tests/test_xcode4_workspace.lua +++ b/modules/xcode/tests/test_xcode4_workspace.lua @@ -7,7 +7,8 @@ --- local suite = test.declare("xcode4_workspace") - local xcode = premake.modules.xcode + local p = premake + local xcode = p.modules.xcode -- diff --git a/modules/xcode/tests/test_xcode_dependencies.lua b/modules/xcode/tests/test_xcode_dependencies.lua index 6bb952d7..d9b9dc0e 100644 --- a/modules/xcode/tests/test_xcode_dependencies.lua +++ b/modules/xcode/tests/test_xcode_dependencies.lua @@ -5,7 +5,8 @@ -- local suite = test.declare("xcode_deps") - local xcode = premake.modules.xcode + local p = premake + local xcode = p.modules.xcode --------------------------------------------------------------------------- @@ -35,9 +36,9 @@ end local function prepare() - wks = premake.oven.bakeWorkspace(wks) + wks = p.oven.bakeWorkspace(wks) xcode.prepareWorkspace(wks) - local prj3 = premake.workspace.getproject(wks, 1) + local prj3 = p.workspace.getproject(wks, 1) --prj2 = test.getproject(wks, 2) tr = xcode.buildprjtree(prj3) end diff --git a/modules/xcode/tests/test_xcode_project.lua b/modules/xcode/tests/test_xcode_project.lua index de9d02e1..9c89fa14 100644 --- a/modules/xcode/tests/test_xcode_project.lua +++ b/modules/xcode/tests/test_xcode_project.lua @@ -4,7 +4,8 @@ -- Copyright (c) 2009-2011 Jason Perkins and the Premake project -- local suite = test.declare("xcode_project") - local xcode = premake.modules.xcode + local p = premake + local xcode = p.modules.xcode @@ -21,13 +22,13 @@ function suite.setup() _TARGET_OS = "macosx" _ACTION = "xcode4" - premake.eol("\n") + p.eol("\n") xcode.used_ids = { } -- reset the list of generated IDs wks = test.createWorkspace() end local function prepare() - wks = premake.oven.bakeWorkspace(wks) + wks = p.oven.bakeWorkspace(wks) xcode.prepareWorkspace(wks) local prj = test.getproject(wks, 1) tr = xcode.buildprjtree(prj) @@ -404,7 +405,7 @@ prepare() xcode.PBXGroup(tr) - local str = premake.captured() + local str = p.captured() --test.istrue(str:find('path = "RequiresQuoting%+%+";')) end @@ -2031,7 +2032,7 @@ function suite.defaultVisibility_settingIsFound() prepare() xcode.XCBuildConfiguration(tr) - local str = premake.captured() + local str = p.captured() test.istrue(str:find('GCC_SYMBOLS_PRIVATE_EXTERN')) end @@ -2039,7 +2040,7 @@ end function suite.defaultVisibilitySetting_setToNo() prepare() xcode.XCBuildConfiguration(tr) - local str = premake.captured() + local str = p.captured() test.istrue(str:find('GCC_SYMBOLS_PRIVATE_EXTERN = NO;')) end @@ -2047,7 +2048,7 @@ function suite.releaseBuild_onlyDefaultArch_equalsNo() optimize "On" prepare() xcode.XCBuildConfiguration_Project(tr, tr.configs[2]) - local str = premake.captured() + local str = p.captured() test.istrue(str:find('ONLY_ACTIVE_ARCH = NO;')) end @@ -2056,6 +2057,6 @@ function suite.debugBuild_onlyDefaultArch_equalsYes() prepare() xcode.XCBuildConfiguration_Project(tr, tr.configs[1]) - local str = premake.captured() + local str = p.captured() test.istrue(str:find('ONLY_ACTIVE_ARCH = YES;')) end diff --git a/modules/xcode/xcode4_workspace.lua b/modules/xcode/xcode4_workspace.lua index b1e0e5c0..58bf0fd1 100644 --- a/modules/xcode/xcode4_workspace.lua +++ b/modules/xcode/xcode4_workspace.lua @@ -38,7 +38,7 @@ function m.workspaceTail() -- Don't output final newline. Xcode doesn't. - premake.out('') + p.out('') end diff --git a/modules/xcode/xcode_common.lua b/modules/xcode/xcode_common.lua index de7cd4de..c15992ba 100644 --- a/modules/xcode/xcode_common.lua +++ b/modules/xcode/xcode_common.lua @@ -287,7 +287,7 @@ function xcode.getxcodeprojname(prj) -- if there is a workspace with matching name, then use "projectname1.xcodeproj" -- just get something working for now - local fname = premake.filename(prj, ".xcodeproj") + local fname = p.filename(prj, ".xcodeproj") return fname end @@ -336,7 +336,7 @@ -- create and cache a list of supported platforms wks.xcode = { } - for prj in premake.workspace.eachproject(wks) do + for prj in p.workspace.eachproject(wks) do -- need a configuration to get the target information local cfg = project.getconfig(prj, prj.configurations[1], prj.platforms[1]) @@ -346,7 +346,7 @@ bundlepath = cfg.project.name end - local node = premake.tree.new(path.getname(bundlepath)) + local node = p.tree.new(path.getname(bundlepath)) node.cfg = cfg node.id = xcode.newid(node.name, "product") @@ -1065,13 +1065,13 @@ local includedirs = project.getrelative(cfg.project, cfg.includedirs) for i,v in ipairs(includedirs) do - cfg.includedirs[i] = premake.quoted(v) + cfg.includedirs[i] = p.quoted(v) end settings['USER_HEADER_SEARCH_PATHS'] = cfg.includedirs local sysincludedirs = project.getrelative(cfg.project, cfg.sysincludedirs) for i,v in ipairs(sysincludedirs) do - cfg.sysincludedirs[i] = premake.quoted(v) + cfg.sysincludedirs[i] = p.quoted(v) end if not table.isempty(cfg.sysincludedirs) then table.insert(cfg.sysincludedirs, "$(inherited)") @@ -1079,19 +1079,19 @@ settings['HEADER_SEARCH_PATHS'] = cfg.sysincludedirs for i,v in ipairs(cfg.libdirs) do - cfg.libdirs[i] = premake.project.getrelative(cfg.project, cfg.libdirs[i]) + cfg.libdirs[i] = p.project.getrelative(cfg.project, cfg.libdirs[i]) end settings['LIBRARY_SEARCH_PATHS'] = cfg.libdirs for i,v in ipairs(cfg.frameworkdirs) do - cfg.frameworkdirs[i] = premake.project.getrelative(cfg.project, cfg.frameworkdirs[i]) + cfg.frameworkdirs[i] = p.project.getrelative(cfg.project, cfg.frameworkdirs[i]) end settings['FRAMEWORK_SEARCH_PATHS'] = cfg.frameworkdirs local objDir = path.getrelative(tr.project.location, cfg.objdir) settings['OBJROOT'] = objDir - settings['ONLY_ACTIVE_ARCH'] = iif(premake.config.isDebugBuild(cfg), 'YES', 'NO') + settings['ONLY_ACTIVE_ARCH'] = iif(p.config.isDebugBuild(cfg), 'YES', 'NO') -- build list of "other" C/C++ flags local checks = { diff --git a/modules/xcode/xcode_project.lua b/modules/xcode/xcode_project.lua index e823e6f7..8a968e46 100644 --- a/modules/xcode/xcode_project.lua +++ b/modules/xcode/xcode_project.lua @@ -145,7 +145,7 @@ xcnode.targetdependid = xcode.newid(xcnode.name, "targdep") -- create a grandchild node for the dependency's link target - local lprj = premake.workspace.findproject(prj.workspace, dep.name) + local lprj = p.workspace.findproject(prj.workspace, dep.name) local cfg = project.findClosestMatch(lprj, prj.configurations[1]) node = tree.insert(xcnode, tree.new(cfg.linktarget.name)) node.path = cfg.linktarget.fullpath diff --git a/src/_premake_main.lua b/src/_premake_main.lua index 77e956bd..3e13a7c2 100644 --- a/src/_premake_main.lua +++ b/src/_premake_main.lua @@ -96,7 +96,7 @@ function m.prepareEnvironment() math.randomseed(os.time()) _PREMAKE_DIR = path.getdirectory(_PREMAKE_COMMAND) - premake.path = premake.path .. ";" .. _PREMAKE_DIR .. ";" .. _MAIN_SCRIPT_DIR + p.path = p.path .. ";" .. _PREMAKE_DIR .. ";" .. _MAIN_SCRIPT_DIR end @@ -171,14 +171,14 @@ -- The "next-gen" actions have now replaced their deprecated counterparts. -- Provide a warning for a little while before I remove them entirely. if _ACTION and _ACTION:endswith("ng") then - premake.warnOnce(_ACTION, "'%s' has been deprecated; use '%s' instead", _ACTION, _ACTION:sub(1, -3)) + p.warnOnce(_ACTION, "'%s' has been deprecated; use '%s' instead", _ACTION, _ACTION:sub(1, -3)) end - premake.action.set(_ACTION) + p.action.set(_ACTION) -- Allow the action to initialize stuff. - local action = premake.action.current() + local action = p.action.current() if action then - premake.action.initialize(action.trigger) + p.action.initialize(action.trigger) end end @@ -218,13 +218,13 @@ end if (_OPTIONS["help"]) then - premake.showhelp() + p.showhelp() os.exit(1) end -- Validate the command-line arguments. This has to happen after the -- script has run to allow for project-specific options - ok, err = premake.option.validate(_OPTIONS) + ok, err = p.option.validate(_OPTIONS) if not ok then print("Error: " .. err) os.exit(1) @@ -237,7 +237,7 @@ os.exit(1) end - local action = premake.action.current() + local action = p.action.current() if not action then print("Error: no such action '" .. _ACTION .. "'") os.exit(1) @@ -268,7 +268,7 @@ function m.bake() if p.action.isConfigurable() then - premake.oven.bake() + p.oven.bake() end end @@ -317,7 +317,7 @@ --- function m.preAction() - local action = premake.action.current() + local action = p.action.current() printf("Running action '%s'...", action.trigger) end @@ -327,8 +327,8 @@ --- function m.callAction() - local action = premake.action.current() - premake.action.call(action.trigger) + local action = p.action.current() + p.action.call(action.trigger) end diff --git a/src/actions/make/_make.lua b/src/actions/make/_make.lua index dbd09b02..d9c5d85b 100644 --- a/src/actions/make/_make.lua +++ b/src/actions/make/_make.lua @@ -4,9 +4,9 @@ -- Copyright (c) 2002-2015 Jason Perkins and the Premake project -- - premake.make = {} - local p = premake + p.make = {} + local make = p.make local project = p.project @@ -34,32 +34,32 @@ end, onWorkspace = function(wks) - premake.escaper(make.esc) - premake.generate(wks, make.getmakefilename(wks, false), make.generate_workspace) + p.escaper(make.esc) + p.generate(wks, make.getmakefilename(wks, false), make.generate_workspace) end, onProject = function(prj) - premake.escaper(make.esc) + p.escaper(make.esc) local makefile = make.getmakefilename(prj, true) - if prj.kind == premake.UTILITY then - premake.generate(prj, makefile, make.utility.generate) - elseif prj.kind == premake.MAKEFILE then - premake.generate(prj, makefile, make.makefile.generate) + if prj.kind == p.UTILITY then + p.generate(prj, makefile, make.utility.generate) + elseif prj.kind == p.MAKEFILE then + p.generate(prj, makefile, make.makefile.generate) else if project.isdotnet(prj) then - premake.generate(prj, makefile, make.cs.generate) + p.generate(prj, makefile, make.cs.generate) elseif project.isc(prj) or project.iscpp(prj) then - premake.generate(prj, makefile, make.cpp.generate) + p.generate(prj, makefile, make.cpp.generate) end end end, onCleanWorkspace = function(wks) - premake.clean.file(wks, make.getmakefilename(wks, false)) + p.clean.file(wks, make.getmakefilename(wks, false)) end, onCleanProject = function(prj) - premake.clean.file(prj, make.getmakefilename(prj, true)) + p.clean.file(prj, make.getmakefilename(prj, true)) end } @@ -144,7 +144,7 @@ function make.header(target) local kind = iif(target.project, "project", "workspace") - _p('# %s %s makefile autogenerated by Premake', premake.action.current().shortname, kind) + _p('# %s %s makefile autogenerated by Premake', p.action.current().shortname, kind) _p('') if kind == "workspace" then @@ -205,7 +205,7 @@ if #result then result = result .. " " end - result = result .. premake.quoted(v) + result = result .. p.quoted(v) end return result else @@ -236,7 +236,7 @@ --------------------------------------------------------------------------- function make.objdir(cfg) - _x(' OBJDIR = %s', premake.esc(project.getrelative(cfg.project, cfg.objdir))) + _x(' OBJDIR = %s', p.esc(project.getrelative(cfg.project, cfg.objdir))) end diff --git a/src/actions/make/make_cpp.lua b/src/actions/make/make_cpp.lua index 07addc0e..fb3a227f 100644 --- a/src/actions/make/make_cpp.lua +++ b/src/actions/make/make_cpp.lua @@ -16,7 +16,7 @@ --- --- Add namespace for element definition lists for premake.callarray() +-- Add namespace for element definition lists for p.callarray() --- cpp.elements = {} @@ -44,8 +44,8 @@ end function make.cpp.generate(prj) - premake.eol("\n") - premake.callArray(cpp.elements.makefile, prj) + p.eol("\n") + p.callArray(cpp.elements.makefile, prj) end @@ -84,13 +84,13 @@ -- identify the toolset used by this configurations (would be nicer if -- this were computed and stored with the configuration up front) - local toolset = premake.tools[_OPTIONS.cc or cfg.toolset or "gcc"] + local toolset = p.tools[_OPTIONS.cc or cfg.toolset or "gcc"] if not toolset then error("Invalid toolset '" .. cfg.toolset .. "'") end _x('ifeq ($(config),%s)', cfg.shortname) - premake.callArray(cpp.elements.configuration, cfg, toolset) + p.callArray(cpp.elements.configuration, cfg, toolset) _p('endif') _p('') end @@ -122,7 +122,7 @@ function make.cppFileRules(prj) local tr = project.getsourcetree(prj) - premake.tree.traverse(tr, { + p.tree.traverse(tr, { onleaf = function(node, depth) -- check to see if this file has custom rules local rules @@ -207,7 +207,7 @@ -- now walk the list of files in the project local tr = project.getsourcetree(prj) - premake.tree.traverse(tr, { + p.tree.traverse(tr, { onleaf = function(node, depth) -- figure out what configurations contain this file, and -- if it uses custom build rules @@ -316,7 +316,7 @@ function make.cppAllRules(cfg, toolset) - if cfg.system == premake.MACOSX and cfg.kind == premake.WINDOWEDAPP then + if cfg.system == p.MACOSX and cfg.kind == p.WINDOWEDAPP then _p('all: prebuild prelink $(TARGET) $(dir $(TARGETDIR))PkgInfo $(dir $(TARGETDIR))Info.plist') _p('\t@:') _p('') @@ -423,7 +423,7 @@ function make.ldDeps(cfg, toolset) local deps = config.getlinks(cfg, "siblings", "fullpath") - _p(' LDDEPS +=%s', make.list(premake.esc(deps))) + _p(' LDDEPS +=%s', make.list(p.esc(deps))) end @@ -440,13 +440,13 @@ function make.linkCmd(cfg, toolset) - if cfg.kind == premake.STATICLIB then - if cfg.architecture == premake.UNIVERSAL then + if cfg.kind == p.STATICLIB then + if cfg.architecture == p.UNIVERSAL then _p(' LINKCMD = libtool -o "$@" $(OBJECTS)') else _p(' LINKCMD = $(AR) ' .. (toolset.arargs or '-rcs') ..' "$@" $(OBJECTS)') end - elseif cfg.kind == premake.UTILITY then + elseif cfg.kind == p.UTILITY then -- Empty LINKCMD for Utility (only custom build rules) _p(' LINKCMD =') else diff --git a/src/actions/make/make_csharp.lua b/src/actions/make/make_csharp.lua index 01d622a0..f629ee95 100644 --- a/src/actions/make/make_csharp.lua +++ b/src/actions/make/make_csharp.lua @@ -4,16 +4,17 @@ -- Copyright (c) 2002-2013 Jason Perkins and the Premake project -- - premake.make.cs = {} - local make = premake.make - local cs = premake.make.cs - local project = premake.project - local config = premake.config - local fileconfig = premake.fileconfig + local p = premake + p.make.cs = {} + local make = p.make + local cs = p.make.cs + local project = p.project + local config = p.config + local fileconfig = p.fileconfig -- --- Add namespace for element definition lists for premake.callarray() +-- Add namespace for element definition lists for p.callarray() -- cs.elements = {} @@ -52,9 +53,9 @@ -- function make.cs.generate(prj) - premake.eol("\n") - local toolset = premake.tools.dotnet - premake.callArray(cs.elements.makefile, prj, toolset) + p.eol("\n") + local toolset = p.tools.dotnet + p.callArray(cs.elements.makefile, prj, toolset) end @@ -79,7 +80,7 @@ function make.csConfigs(prj, toolset) for cfg in project.eachconfig(prj) do _x('ifeq ($(config),%s)', cfg.shortname) - premake.callArray(cs.elements.configuration, cfg, toolset) + p.callArray(cs.elements.configuration, cfg, toolset) _p('endif') _p('') end @@ -98,7 +99,7 @@ if dir ~= "." then name = name .. path.translate(dir, ".") .. "." end - return "$(OBJDIR)/" .. premake.esc(name .. path.getbasename(fname)) .. ".resources" + return "$(OBJDIR)/" .. p.esc(name .. path.getbasename(fname)) .. ".resources" else return fname end @@ -111,7 +112,7 @@ function cs.listsources(prj, selector) local tr = project.getsourcetree(prj) - premake.tree.traverse(tr, { + p.tree.traverse(tr, { onleaf = function(node, depth) local value = selector(node) if value then @@ -186,9 +187,9 @@ function make.csResponseRules(prj) - local toolset = premake.tools.dotnet + local toolset = p.tools.dotnet local ext = make.getmakefilename(prj, true) - local makefile = path.getname(premake.filename(prj, ext)) + local makefile = path.getname(p.filename(prj, ext)) local response = make.cs.getresponsefilename(prj) _p('$(RESPONSE): %s', makefile) @@ -202,7 +203,7 @@ local sep = os.istarget("windows") and "\\" or "/" local tr = project.getsourcetree(prj) - premake.tree.traverse(tr, { + p.tree.traverse(tr, { onleaf = function(node, depth) if toolset.fileinfo(node).action == "Compile" then _x('\t@echo %s >> $(RESPONSE)', path.translate(node.relpath, sep)) @@ -232,10 +233,10 @@ --[[ -- porting from 4.x _p('# Per-configuration copied file rules') - for cfg in premake.eachconfig(prj) do + for cfg in p.eachconfig(prj) do _x('ifneq (,$(findstring %s,$(config)))', cfg.name:lower()) for target, source in pairs(cfgpairs[cfg]) do - premake.make_copyrule(source, target) + p.make_copyrule(source, target) end _p('endif') _p('') @@ -243,7 +244,7 @@ _p('# Copied file rules') for target, source in pairs(copypairs) do - premake.make_copyrule(source, target) + p.make_copyrule(source, target) end _p('# Embedded file rules') @@ -264,7 +265,7 @@ function make.csLinkCmd(cfg, toolset) - local deps = premake.esc(config.getlinks(cfg, "dependencies", "fullpath")) + local deps = p.esc(config.getlinks(cfg, "dependencies", "fullpath")) _p(' DEPENDS =%s', make.list(deps)) _p(' REFERENCES = %s', table.implode(deps, "/r:", "", " ")) end @@ -276,10 +277,10 @@ local cfg = project.getfirstconfig(prj) local kindflag = "/t:" .. toolset.getkind(cfg):lower() - local libdirs = table.implode(premake.esc(cfg.libdirs), "/lib:", "", " ") + local libdirs = table.implode(p.esc(cfg.libdirs), "/lib:", "", " ") _p('FLAGS += %s', table.concat(table.join(kindflag, libdirs), " ")) - local refs = premake.esc(config.getlinks(cfg, "system", "fullpath")) + local refs = p.esc(config.getlinks(cfg, "system", "fullpath")) _p('REFERENCES += %s', table.implode(refs, "/r:", "", " ")) _p('') end diff --git a/src/actions/make/make_makefile.lua b/src/actions/make/make_makefile.lua index 0dea1efd..739995b0 100644 --- a/src/actions/make/make_makefile.lua +++ b/src/actions/make/make_makefile.lua @@ -14,7 +14,7 @@ local fileconfig = p.fileconfig --- --- Add namespace for element definition lists for premake.callarray() +-- Add namespace for element definition lists for p.callarray() --- makefile.elements = {} @@ -30,8 +30,8 @@ } function make.makefile.generate(prj) - premake.eol("\n") - premake.callarray(make, makefile.elements.makefile, prj) + p.eol("\n") + p.callarray(make, makefile.elements.makefile, prj) end @@ -46,13 +46,13 @@ -- identify the toolset used by this configurations (would be nicer if -- this were computed and stored with the configuration up front) - local toolset = premake.tools[cfg.toolset or "gcc"] + local toolset = p.tools[cfg.toolset or "gcc"] if not toolset then error("Invalid toolset '" .. cfg.toolset .. "'") end _x('ifeq ($(config),%s)', cfg.shortname) - premake.callarray(make, makefile.elements.configuration, cfg, toolset) + p.callarray(make, makefile.elements.configuration, cfg, toolset) _p('endif') _p('') end diff --git a/src/actions/make/make_utility.lua b/src/actions/make/make_utility.lua index 596334ee..bb10205f 100644 --- a/src/actions/make/make_utility.lua +++ b/src/actions/make/make_utility.lua @@ -14,7 +14,7 @@ local fileconfig = p.fileconfig --- --- Add namespace for element definition lists for premake.callarray() +-- Add namespace for element definition lists for p.callarray() --- utility.elements = {} @@ -30,8 +30,8 @@ } function make.utility.generate(prj) - premake.eol("\n") - premake.callarray(make, utility.elements.makefile, prj) + p.eol("\n") + p.callarray(make, utility.elements.makefile, prj) end @@ -46,13 +46,13 @@ -- identify the toolset used by this configurations (would be nicer if -- this were computed and stored with the configuration up front) - local toolset = premake.tools[cfg.toolset or "gcc"] + local toolset = p.tools[cfg.toolset or "gcc"] if not toolset then error("Invalid toolset '" .. cfg.toolset .. "'") end _x('ifeq ($(config),%s)', cfg.shortname) - premake.callarray(make, utility.elements.configuration, cfg, toolset) + p.callarray(make, utility.elements.configuration, cfg, toolset) _p('endif') _p('') end diff --git a/src/actions/make/make_workspace.lua b/src/actions/make/make_workspace.lua index a2e9812f..e171b304 100644 --- a/src/actions/make/make_workspace.lua +++ b/src/actions/make/make_workspace.lua @@ -58,7 +58,7 @@ function make.cleanrules(wks) _p('clean:') for prj in p.workspace.eachproject(wks) do - local prjpath = premake.filename(prj, make.getmakefilename(prj, true)) + local prjpath = p.filename(prj, make.getmakefilename(prj, true)) local prjdir = path.getdirectory(path.getrelative(wks.location, prjpath)) local prjname = path.getname(prjpath) _x(1,'@${MAKE} --no-print-directory -C %s -f %s clean', prjdir, prjname) @@ -101,7 +101,7 @@ -- function make.projects(wks) - _p('PROJECTS := %s', table.concat(premake.esc(table.extract(wks.projects, "name")), " ")) + _p('PROJECTS := %s', table.concat(p.esc(table.extract(wks.projects, "name")), " ")) _p('') end @@ -167,14 +167,14 @@ for prj in p.workspace.eachproject(wks) do local deps = project.getdependencies(prj) deps = table.extract(deps, "name") - _p('%s:%s', premake.esc(prj.name), make.list(deps)) + _p('%s:%s', p.esc(prj.name), make.list(deps)) local cfgvar = make.tovar(prj.name) _p('ifneq (,$(%s_config))', cfgvar) _p(1,'@echo "==== Building %s ($(%s_config)) ===="', prj.name, cfgvar) - local prjpath = premake.filename(prj, make.getmakefilename(prj, true)) + local prjpath = p.filename(prj, make.getmakefilename(prj, true)) local prjdir = path.getdirectory(path.getrelative(wks.location, prjpath)) local prjname = path.getname(prjpath) diff --git a/src/actions/vstudio/_vstudio.lua b/src/actions/vstudio/_vstudio.lua index e0b8e0c0..a29a2d0e 100644 --- a/src/actions/vstudio/_vstudio.lua +++ b/src/actions/vstudio/_vstudio.lua @@ -4,10 +4,10 @@ -- Copyright (c) 2008-2013 Jason Perkins and the Premake project -- - premake.vstudio = {} - local vstudio = premake.vstudio - local p = premake + p.vstudio = {} + local vstudio = p.vstudio + local project = p.project local config = p.config @@ -294,8 +294,8 @@ -- function vstudio.archFromPlatform(platform) - local system = premake.api.checkValue(premake.fields.system, platform) - local arch = premake.api.checkValue(premake.fields.architecture, platform) + local system = p.api.checkValue(p.fields.system, platform) + local arch = p.api.checkValue(p.fields.architecture, platform) return architecture(system, arch or platform:lower()) end @@ -308,7 +308,7 @@ if locale then local culture = vstudio._cultures[locale] if not culture then - premake.warnOnce("Locale" .. locale, 'Unsupported locale "%s"', locale) + p.warnOnce("Locale" .. locale, 'Unsupported locale "%s"', locale) end return culture end @@ -341,7 +341,7 @@ -- function vstudio.isMakefile(cfg) - return (cfg.kind == premake.MAKEFILE or cfg.kind == premake.NONE) + return (cfg.kind == p.MAKEFILE or cfg.kind == p.NONE) end @@ -443,7 +443,7 @@ extension = iif(_ACTION > "vs2008", ".vcxproj", ".vcproj") end - return premake.filename(prj, extension) + return p.filename(prj, extension) end diff --git a/src/actions/vstudio/vs2005.lua b/src/actions/vstudio/vs2005.lua index 91630755..0d8b6695 100644 --- a/src/actions/vstudio/vs2005.lua +++ b/src/actions/vstudio/vs2005.lua @@ -4,9 +4,9 @@ -- Copyright (c) 2008-2015 Jason Perkins and the Premake project -- - premake.vstudio.vs2005 = {} - local p = premake + p.vstudio.vs2005 = {} + local vs2005 = p.vstudio.vs2005 local vstudio = p.vstudio @@ -20,7 +20,7 @@ p.eol("\r\n") p.escaper(vs2005.esc) - premake.generate(wks, ".sln", vstudio.sln2005.generate) + p.generate(wks, ".sln", vstudio.sln2005.generate) end @@ -29,8 +29,8 @@ p.eol("\r\n") p.escaper(vs2005.esc) - if premake.project.isdotnet(prj) then - premake.generate(prj, ".csproj", vstudio.cs2005.generate) + if p.project.isdotnet(prj) then + p.generate(prj, ".csproj", vstudio.cs2005.generate) -- Skip generation of empty user files local user = p.capture(function() vstudio.cs2005.generateUser(prj) end) @@ -38,7 +38,7 @@ p.generate(prj, ".csproj.user", function() p.outln(user) end) end else - premake.generate(prj, ".vcproj", vstudio.vc200x.generate) + p.generate(prj, ".vcproj", vstudio.vc200x.generate) -- Skip generation of empty user files local user = p.capture(function() vstudio.vc200x.generateUser(prj) end) diff --git a/src/actions/vstudio/vs2005_csproj.lua b/src/actions/vstudio/vs2005_csproj.lua index 207078f0..b6d5ab01 100644 --- a/src/actions/vstudio/vs2005_csproj.lua +++ b/src/actions/vstudio/vs2005_csproj.lua @@ -4,9 +4,9 @@ -- Copyright (c) 2009-2014 Jason Perkins and the Premake project -- - premake.vstudio.cs2005 = {} - local p = premake + p.vstudio.cs2005 = {} + local vstudio = p.vstudio local cs2005 = p.vstudio.cs2005 local project = p.project @@ -35,7 +35,7 @@ function cs2005.generate(prj) p.utf8() - premake.callarray(cs2005, cs2005.elements.project, prj) + p.callarray(cs2005, cs2005.elements.project, prj) _p(1,'') cs2005.files(prj) @@ -55,7 +55,7 @@ function cs2005.projectElement(prj) local ver = '' - local action = premake.action.current() + local action = p.action.current() if action.vstudio.toolsVersion then ver = string.format(' ToolsVersion="%s"', action.vstudio.toolsVersion) end @@ -86,7 +86,7 @@ function cs2005.projectProperties(prj) _p(1,'') local cfg = project.getfirstconfig(prj) - premake.callarray(cs2005, cs2005.elements.projectProperties, cfg) + p.callarray(cs2005, cs2005.elements.projectProperties, cfg) _p(1,'') end @@ -109,7 +109,7 @@ end function cs2005.configuration(cfg) - premake.callarray(cs2005, cs2005.elements.configuration, cfg) + p.callarray(cs2005, cs2005.elements.configuration, cfg) _p(1,'') end @@ -142,7 +142,7 @@ -- Process any sub-elements required by this file; choose the write -- element form to use based on the results. - local contents = premake.capture(function () + local contents = p.capture(function () -- Try to write file-level elements in the same order as Visual Studio local elements = { "AutoGen", @@ -190,7 +190,7 @@ local firstcfg = project.getfirstconfig(prj) local tr = project.getsourcetree(prj) - premake.tree.traverse(tr, { + p.tree.traverse(tr, { onleaf = function(node, depth) -- test if all fileinfo's are going to be the same for each config. local allsame = true @@ -373,7 +373,7 @@ local packageAPIInfo = vstudio.nuget2010.packageAPIInfo(prj, package) local cfg = p.project.getfirstconfig(prj) - local action = premake.action.current() + local action = p.action.current() local targetFramework = cfg.dotnetframework or action.vstudio.targetFramework -- This is a bit janky. To compare versions, we extract all @@ -601,7 +601,7 @@ function cs2005.productVersion(cfg) - local action = premake.action.current() + local action = p.action.current() if action.vstudio.productVersion then _p(2,'%s', action.vstudio.productVersion) end @@ -625,7 +625,7 @@ function cs2005.schemaVersion(cfg) - local action = premake.action.current() + local action = p.action.current() if action.vstudio.csprojSchemaVersion then _p(2,'%s', action.vstudio.csprojSchemaVersion) end @@ -633,7 +633,7 @@ function cs2005.targetFrameworkVersion(cfg) - local action = premake.action.current() + local action = p.action.current() local framework = cfg.dotnetframework or action.vstudio.targetFramework if framework then _p(2,'v%s', framework) diff --git a/src/actions/vstudio/vs2005_solution.lua b/src/actions/vstudio/vs2005_solution.lua index 6ce5fb02..cad2ff75 100644 --- a/src/actions/vstudio/vs2005_solution.lua +++ b/src/actions/vstudio/vs2005_solution.lua @@ -4,9 +4,9 @@ -- Copyright (c) 2009-2015 Jason Perkins and the Premake project -- - premake.vstudio.sln2005 = {} - local p = premake + p.vstudio.sln2005 = {} + local vstudio = p.vstudio local sln2005 = p.vstudio.sln2005 local project = p.project @@ -14,7 +14,7 @@ --- --- Add namespace for element definition lists for premake.callArray() +-- Add namespace for element definition lists for p.callArray() --- sln2005.elements = {} @@ -41,8 +41,8 @@ function sln2005.generate(wks) -- Mark the file as Unicode - premake.utf8() - premake.outln('') + p.utf8() + p.outln('') sln2005.reorderProjects(wks) @@ -62,7 +62,7 @@ -- function sln2005.header() - local action = premake.action.current() + local action = p.action.current() p.w('Microsoft Visual Studio Solution File, Format Version %d.00', action.vstudio.solutionVersion) p.w('# Visual Studio %s', action.vstudio.versionName) end @@ -200,7 +200,7 @@ function sln2005.build0(cfg, context) - if not context.excluded and context.prjCfg.kind ~= premake.NONE then + if not context.excluded and context.prjCfg.kind ~= p.NONE then p.w('{%s}.%s.Build.0 = %s|%s', context.prj.uuid, context.descriptor, context.platform, context.architecture) end end diff --git a/src/actions/vstudio/vs2008.lua b/src/actions/vstudio/vs2008.lua index 07e131c9..5da95b9f 100644 --- a/src/actions/vstudio/vs2008.lua +++ b/src/actions/vstudio/vs2008.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2008-2013 Jason Perkins and the Premake project -- - premake.vstudio.vs2008 = {} - local vs2008 = premake.vstudio.vs2008 - local vstudio = premake.vstudio + local p = premake + p.vstudio.vs2008 = {} + local vs2008 = p.vstudio.vs2008 + local vstudio = p.vstudio --- diff --git a/src/actions/vstudio/vs200x_vcproj.lua b/src/actions/vstudio/vs200x_vcproj.lua index 299b7adc..e42e8cc4 100644 --- a/src/actions/vstudio/vs200x_vcproj.lua +++ b/src/actions/vstudio/vs200x_vcproj.lua @@ -4,10 +4,10 @@ -- Copyright (c) 2009-2014 Jason Perkins and the Premake project -- - premake.vstudio.vc200x = {} - local m = premake.vstudio.vc200x - local p = premake + p.vstudio.vc200x = {} + local m = p.vstudio.vc200x + local vstudio = p.vstudio local context = p.context local project = p.project @@ -219,7 +219,7 @@ end function m.tools(cfg) - premake.callArray(m.elements.tools, cfg, config.toolset(cfg)) + p.callArray(m.elements.tools, cfg, config.toolset(cfg)) end diff --git a/src/actions/vstudio/vs2010.lua b/src/actions/vstudio/vs2010.lua index df99f540..4ad01840 100644 --- a/src/actions/vstudio/vs2010.lua +++ b/src/actions/vstudio/vs2010.lua @@ -4,9 +4,9 @@ -- Copyright (c) 2009-2015 Jason Perkins and the Premake project -- - premake.vstudio.vs2010 = {} - local p = premake + p.vstudio.vs2010 = {} + local vs2010 = p.vstudio.vs2010 local vstudio = p.vstudio local project = p.project @@ -69,7 +69,7 @@ -- Only generate a filters file if the source tree actually has subfolders if tree.hasbranches(project.getsourcetree(prj)) then - premake.generate(prj, ".vcxproj.filters", vstudio.vc2010.generateFilters) + p.generate(prj, ".vcxproj.filters", vstudio.vc2010.generateFilters) end end diff --git a/src/actions/vstudio/vs2010_nuget.lua b/src/actions/vstudio/vs2010_nuget.lua index ae9f305a..a0ced58e 100644 --- a/src/actions/vstudio/vs2010_nuget.lua +++ b/src/actions/vstudio/vs2010_nuget.lua @@ -4,9 +4,9 @@ -- Copyright (c) 2016 Jason Perkins and the Premake project -- - premake.vstudio.nuget2010 = {} - local p = premake + p.vstudio.nuget2010 = {} + local vstudio = p.vstudio local nuget2010 = p.vstudio.nuget2010 local cs2005 = p.vstudio.cs2005 @@ -30,7 +30,7 @@ function nuget2010.packageFramework(prj) if p.project.isdotnet(prj) then local cfg = p.project.getfirstconfig(prj) - local action = premake.action.current() + local action = p.action.current() local framework = cfg.dotnetframework or action.vstudio.targetFramework return cs2005.formatNuGetFrameworkVersion(framework) else diff --git a/src/actions/vstudio/vs2010_rules_props.lua b/src/actions/vstudio/vs2010_rules_props.lua index 6209b208..8923af87 100644 --- a/src/actions/vstudio/vs2010_rules_props.lua +++ b/src/actions/vstudio/vs2010_rules_props.lua @@ -5,14 +5,12 @@ -- - premake.vstudio.vs2010.rules = {} - premake.vstudio.vs2010.rules.props = {} - - local m = premake.vstudio.vs2010.rules.props - m.elements = {} - local p = premake + p.vstudio.vs2010.rules = {} + p.vstudio.vs2010.rules.props = {} + local m = p.vstudio.vs2010.rules.props + m.elements = {} --- diff --git a/src/actions/vstudio/vs2010_rules_targets.lua b/src/actions/vstudio/vs2010_rules_targets.lua index 6503469e..b0da8775 100644 --- a/src/actions/vstudio/vs2010_rules_targets.lua +++ b/src/actions/vstudio/vs2010_rules_targets.lua @@ -4,12 +4,11 @@ -- Copyright (c) 2014 Jason Perkins and the Premake project --- - premake.vstudio.vs2010.rules.targets = {} - - local m = premake.vstudio.vs2010.rules.targets - m.elements = {} - local p = premake + p.vstudio.vs2010.rules.targets = {} + + local m = p.vstudio.vs2010.rules.targets + m.elements = {} --- diff --git a/src/actions/vstudio/vs2010_rules_xml.lua b/src/actions/vstudio/vs2010_rules_xml.lua index 7090f8a9..b5a56f7b 100644 --- a/src/actions/vstudio/vs2010_rules_xml.lua +++ b/src/actions/vstudio/vs2010_rules_xml.lua @@ -4,12 +4,11 @@ -- Copyright (c) 2014 Jason Perkins and the Premake project -- - premake.vstudio.vs2010.rules.xml = {} - - local m = premake.vstudio.vs2010.rules.xml - m.elements = {} - local p = premake + p.vstudio.vs2010.rules.xml = {} + + local m = p.vstudio.vs2010.rules.xml + m.elements = {} --- diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index 9d325e12..b4a0bf33 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -4,9 +4,9 @@ -- Copyright (c) 2009-2015 Jason Perkins and the Premake project -- - premake.vstudio.vc2010 = {} - local p = premake + p.vstudio.vc2010 = {} + local vstudio = p.vstudio local project = p.project local config = p.config @@ -17,7 +17,7 @@ --- --- Add namespace for element definition lists for premake.callArray() +-- Add namespace for element definition lists for p.callArray() --- m.elements = {} diff --git a/src/actions/vstudio/vs2010_vcxproj_filters.lua b/src/actions/vstudio/vs2010_vcxproj_filters.lua index 752755d8..279c09a6 100644 --- a/src/actions/vstudio/vs2010_vcxproj_filters.lua +++ b/src/actions/vstudio/vs2010_vcxproj_filters.lua @@ -29,7 +29,7 @@ -- function m.filtersProject() - local action = premake.action.current() + local action = p.action.current() p.push('', action.vstudio.filterToolsVersion or action.vstudio.toolsVersion) end diff --git a/src/actions/vstudio/vs2010_vcxproj_user.lua b/src/actions/vstudio/vs2010_vcxproj_user.lua index ab29a6fa..180a8ec5 100755 --- a/src/actions/vstudio/vs2010_vcxproj_user.lua +++ b/src/actions/vstudio/vs2010_vcxproj_user.lua @@ -53,7 +53,7 @@ -- function m.userProject() - local action = premake.action.current() + local action = p.action.current() p.push('', action.vstudio.toolsVersion) end diff --git a/src/actions/vstudio/vs2012.lua b/src/actions/vstudio/vs2012.lua index e257b664..abdba2c3 100644 --- a/src/actions/vstudio/vs2012.lua +++ b/src/actions/vstudio/vs2012.lua @@ -4,12 +4,11 @@ -- Copyright (c) 2013-2014 Jason Perkins and the Premake project -- - local vstudio = premake.vstudio + local p = premake + local vstudio = p.vstudio local cs2005 = vstudio.cs2005 local vc2010 = vstudio.vc2010 - local p = premake - --- -- Define the Visual Studio 2010 export action. diff --git a/src/actions/vstudio/vs2013.lua b/src/actions/vstudio/vs2013.lua index 0a5c53fc..086f4e76 100644 --- a/src/actions/vstudio/vs2013.lua +++ b/src/actions/vstudio/vs2013.lua @@ -4,9 +4,9 @@ -- Copyright (c) 2013-2014 Jason Perkins and the Premake project -- - premake.vstudio.vc2013 = {} - local p = premake + p.vstudio.vc2013 = {} + local vstudio = p.vstudio local vc2010 = vstudio.vc2010 diff --git a/src/actions/vstudio/vs2015.lua b/src/actions/vstudio/vs2015.lua index 5ddf83a0..7413401b 100644 --- a/src/actions/vstudio/vs2015.lua +++ b/src/actions/vstudio/vs2015.lua @@ -4,9 +4,9 @@ -- Copyright (c) 2015-2015 Jason Perkins and the Premake project -- - premake.vstudio.vc2015 = {} - local p = premake + p.vstudio.vc2015 = {} + local vstudio = p.vstudio local vc2010 = vstudio.vc2010 diff --git a/src/actions/vstudio/vs2017.lua b/src/actions/vstudio/vs2017.lua index 12121e61..95caa77b 100644 --- a/src/actions/vstudio/vs2017.lua +++ b/src/actions/vstudio/vs2017.lua @@ -4,9 +4,9 @@ -- Copyright (c) 2017-2017 Jason Perkins and the Premake project -- - premake.vstudio.vc2017 = {} - local p = premake + p.vstudio.vc2017 = {} + local vstudio = p.vstudio local vc2010 = vstudio.vc2010 diff --git a/src/base/action.lua b/src/base/action.lua index f5e5857a..3820911b 100644 --- a/src/base/action.lua +++ b/src/base/action.lua @@ -7,7 +7,7 @@ local p = premake p.action = {} - local action = premake.action + local action = p.action @@ -62,7 +62,7 @@ end if act.os ~= nil then - premake.warnOnce(act.trigger, "action '" .. act.trigger .. "' sets 'os' field, which is deprecated, use 'targetos' instead.") + p.warnOnce(act.trigger, "action '" .. act.trigger .. "' sets 'os' field, which is deprecated, use 'targetos' instead.") act.targetos = act.os act.os = nil end @@ -272,7 +272,7 @@ -- @return -- True if the configuration is supported, false otherwise. -- - function premake.action.supportsconfig(action, cfg) + function p.action.supportsconfig(action, cfg) if not action then return false end diff --git a/src/base/api.lua b/src/base/api.lua index fb953e32..659290a2 100755 --- a/src/base/api.lua +++ b/src/base/api.lua @@ -8,7 +8,7 @@ local p = premake p.api = {} - local api = premake.api + local api = p.api local configset = p.configset @@ -81,7 +81,7 @@ --- function includeexternal(fname) - local fullPath = premake.findProjectScript(fname) + local fullPath = p.findProjectScript(fname) api._isIncludingExternal = true fname = fullPath or fname dofile(fname) @@ -248,7 +248,7 @@ end -- add this new field to my master list - field, err = premake.field.new(field) + field, err = p.field.new(field) if not field then error(err) end @@ -258,7 +258,7 @@ -- use this information when expanding tokens, to ensure that the paths -- are still well-formed after replacements. - field.paths = premake.field.property(field, "paths") + field.paths = p.field.property(field, "paths") -- Add preprocessed, lowercase keys to the allowed and aliased value -- lists to speed up value checking later on. @@ -281,7 +281,7 @@ return api.storeField(field, value) end - if premake.field.removes(field) then + if p.field.removes(field) then _G["remove" .. name] = function(value) return api.remove(field, value) end @@ -299,9 +299,9 @@ function api.unregister(field) if type(field) == "string" then - field = premake.field.get(field) + field = p.field.get(field) end - premake.field.unregister(field) + p.field.unregister(field) _G[field.name] = nil _G["remove" .. field.name] = nil end @@ -338,7 +338,7 @@ -- function api.addAllowed(fieldName, value) - local field = premake.field.get(fieldName) + local field = p.field.get(fieldName) if not field then error("No such field: " .. fieldName, 2) end @@ -367,7 +367,7 @@ -- function api.addAliases(fieldName, value) - local field = premake.field.get(fieldName) + local field = p.field.get(fieldName) if not field then error("No such field: " .. fieldName, 2) end @@ -395,7 +395,7 @@ -- function api.deprecateField(name, message, handler) - premake.fields[name].deprecated = { + p.fields[name].deprecated = { handler = handler, message = message } @@ -427,7 +427,7 @@ api.deprecateValue(name, v, message, addHandler, removeHandler) end else - local field = premake.fields[name] + local field = p.fields[name] field.deprecated = field.deprecated or {} field.deprecated[value] = { add = addHandler, @@ -490,7 +490,7 @@ if field.deprecated and type(field.deprecated.handler) == "function" then field.deprecated.handler(value) if field.deprecated.message and api._deprecations ~= "off" then - premake.warnOnce(field.name, "the field %s has been deprecated and will be removed.\n %s", field.name, field.deprecated.message) + p.warnOnce(field.name, "the field %s has been deprecated and will be removed.\n %s", field.name, field.deprecated.message) if api._deprecations == "error" then error("deprecation errors enabled", 3) end end end @@ -542,7 +542,7 @@ if handler.remove then handler.remove(value) end if handler.message and api._deprecations ~= "off" then local key = field.name .. "_" .. value - premake.warnOnce(key, "the %s value %s has been deprecated and will be removed.\n %s", field.name, value, handler.message) + p.warnOnce(key, "the %s value %s has been deprecated and will be removed.\n %s", field.name, value, handler.message) if api._deprecations == "error" then error { msg="deprecation errors enabled" } end @@ -648,7 +648,7 @@ handler.add(canonical) if handler.message and api._deprecations ~= "off" then local key = field.name .. "_" .. value - premake.warnOnce(key, "the %s value %s has been deprecated and will be removed.\n %s", field.name, canonical, handler.message) + p.warnOnce(key, "the %s value %s has been deprecated and will be removed.\n %s", field.name, canonical, handler.message) if api._deprecations == "error" then return nil, "deprecation errors enabled" end @@ -1142,7 +1142,7 @@ -- function newaction(a) - premake.action.add(a) + p.action.add(a) end @@ -1154,5 +1154,5 @@ -- function newoption(opt) - premake.option.add(opt) + p.option.add(opt) end diff --git a/src/base/config.lua b/src/base/config.lua index a011ec75..879a5fe2 100755 --- a/src/base/config.lua +++ b/src/base/config.lua @@ -48,7 +48,7 @@ local bundlename = "" local bundlepath = "" - if cfg.system == premake.MACOSX and kind == premake.WINDOWEDAPP then + if cfg.system == p.MACOSX and kind == p.WINDOWEDAPP then bundlename = basename .. ".app" bundlepath = path.join(bundlename, "Contents/MacOS") end @@ -193,8 +193,8 @@ -- is provided, change the kind as import libraries are static. local kind = cfg.kind if project.isnative(cfg.project) then - if cfg.system == premake.WINDOWS and kind == premake.SHAREDLIB and not cfg.flags.NoImportLib then - kind = premake.STATICLIB + if cfg.system == p.WINDOWS and kind == p.SHAREDLIB and not cfg.flags.NoImportLib then + kind = p.STATICLIB end end return config.buildtargetinfo(cfg, kind, "implib") diff --git a/src/base/detoken.lua b/src/base/detoken.lua index 698c9dc9..a8cb0bc5 100644 --- a/src/base/detoken.lua +++ b/src/base/detoken.lua @@ -6,9 +6,9 @@ -- Copyright (c) 2011-2014 Jason Perkins and the Premake project -- - premake.detoken = {} - local p = premake + p.detoken = {} + local detoken = p.detoken diff --git a/src/base/field.lua b/src/base/field.lua index 76d974a1..299039ad 100644 --- a/src/base/field.lua +++ b/src/base/field.lua @@ -12,8 +12,9 @@ -- Copyright (c) 2014 Jason Perkins and the Premake project --- - premake.field = {} - local field = premake.field + local p = premake + p.field = {} + local field = p.field -- Lists to hold all of the registered fields and data kinds @@ -334,14 +335,14 @@ --- -- Override one of the field kind accessor functions. This works just like --- premake.override(), but applies the new function to the internal field +-- p.override(), but applies the new function to the internal field -- description and clears the accessor caches to make sure the change gets -- picked up by future operations. --- function field.override(fieldName, accessorName, func) local kind = field.kind(fieldName) - premake.override(kind, accessorName, func) + p.override(kind, accessorName, func) field._accessors = {} end diff --git a/src/base/fileconfig.lua b/src/base/fileconfig.lua index 81afa395..adf4703c 100644 --- a/src/base/fileconfig.lua +++ b/src/base/fileconfig.lua @@ -4,9 +4,9 @@ -- Copyright (c) 2011-2014 Jason Perkins and the Premake project -- - premake.fileconfig = {} - local p = premake + p.fileconfig = {} + local fileconfig = p.fileconfig local context = p.context local project = p.project @@ -184,7 +184,7 @@ -- function fileconfig.hasFileSettings(fcfg) - for key, field in pairs(premake.fields) do + for key, field in pairs(p.fields) do if field.scopes[1] == "config" then local value = fcfg[field.name] if value then diff --git a/src/base/languages.lua b/src/base/languages.lua index c130432f..156be43a 100644 --- a/src/base/languages.lua +++ b/src/base/languages.lua @@ -4,8 +4,8 @@ -- Copyright (c) 2002-2015 Jason Perkins and the Premake project --- - premake.languages = {} local p = premake + p.languages = {} local languages = p.languages @@ -62,7 +62,7 @@ -- Combined list of all supported languages. --- languages.all = table.join( - languages.c, - languages.cpp, + languages.c, + languages.cpp, languages.dotnet ) diff --git a/src/base/option.lua b/src/base/option.lua index 276f60ad..a8cf8b1f 100644 --- a/src/base/option.lua +++ b/src/base/option.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2002-2014 Jason Perkins and the Premake project -- - premake.option = {} - local m = premake.option + local p = premake + p.option = {} + local m = p.option -- @@ -87,7 +88,7 @@ end -- add it to the master list - premake.option.list[opt.trigger:lower()] = opt + p.option.list[opt.trigger:lower()] = opt -- if it has a default value, set it. if opt.default and not _OPTIONS[opt.trigger] then @@ -107,7 +108,7 @@ -- function m.get(name) - return premake.option.list[name] + return p.option.list[name] end @@ -119,7 +120,7 @@ function m.each() -- sort the list by trigger local keys = { } - for _, option in pairs(premake.option.list) do + for _, option in pairs(p.option.list) do table.insert(keys, option.trigger) end table.sort(keys) @@ -127,7 +128,7 @@ local i = 0 return function() i = i + 1 - return premake.option.list[keys[i]] + return p.option.list[keys[i]] end end @@ -145,7 +146,7 @@ function m.validate(values) for key, value in pairs(values) do -- does this option exist - local opt = premake.option.get(key) + local opt = p.option.get(key) if (not opt) then return false, "invalid option '" .. key .. "'" end diff --git a/src/base/oven.lua b/src/base/oven.lua index 7ce8c9ee..45cef581 100644 --- a/src/base/oven.lua +++ b/src/base/oven.lua @@ -261,7 +261,7 @@ local platform = pairing[2] local cfg = oven.bakeConfig(wks, self, buildcfg, platform) - if premake.action.supportsconfig(premake.action.current(), cfg) then + if p.action.supportsconfig(p.action.current(), cfg) then self.configs[(buildcfg or "*") .. (platform or "")] = cfg end end @@ -405,7 +405,7 @@ local pairings = table.fold(buildcfgs, platforms) for _, pairing in ipairs(pairings) do local cfg = oven.bakeConfig(wks, nil, pairing[1], pairing[2]) - if premake.action.supportsconfig(premake.action.current(), cfg) then + if p.action.supportsconfig(p.action.current(), cfg) then table.insert(configs, cfg) end end diff --git a/src/base/premake.lua b/src/base/premake.lua index cde0c8e2..962c642d 100644 --- a/src/base/premake.lua +++ b/src/base/premake.lua @@ -49,7 +49,7 @@ fn() -- build the result - local captured = premake.captured() + local captured = p.captured() -- free the capture buffer. buffered.close(_captured) @@ -108,7 +108,7 @@ local result = {} local n = #value for i = 1, n do - table.insert(result, premake.esc(value[i])) + table.insert(result, p.esc(value[i])) end return result end @@ -150,13 +150,13 @@ -- function premake.generate(obj, ext, callback) - local output = premake.capture(function () + local output = p.capture(function () _indentLevel = 0 callback(obj) _indentLevel = 0 end) - local fn = premake.filename(obj, ext) + local fn = p.filename(obj, ext) -- make sure output folder exists. local dir = path.getdirectory(fn) @@ -238,8 +238,8 @@ end --- function premake.outln(s) - premake.out(s) - premake.out(_eol or "\n") + p.out(s) + p.out(_eol or "\n") end @@ -260,7 +260,7 @@ end _indentLevel = _indentLevel - (i or 1) else _indentLevel = _indentLevel - 1 - premake.w(i, ...) + p.w(i, ...) end end @@ -281,7 +281,7 @@ end if i == nil or type(i) == "number" then _indentLevel = _indentLevel + (i or 1) else - premake.w(i, ...) + p.w(i, ...) _indentLevel = _indentLevel + 1 end end @@ -324,9 +324,9 @@ end function premake.w(...) if select("#", ...) > 0 then - premake.outln(string.rep(_indentString or "\t", _indentLevel) .. string.format(...)) + p.outln(string.rep(_indentString or "\t", _indentLevel) .. string.format(...)) else - premake.outln(''); + p.outln(''); end end @@ -341,9 +341,9 @@ end function premake.x(msg, ...) local arg = {...} for i = 1, #arg do - arg[i] = premake.esc(arg[i]) + arg[i] = p.esc(arg[i]) end - premake.w(msg, unpack(arg)) + p.w(msg, unpack(arg)) end @@ -359,7 +359,7 @@ end function premake.xmlUtf8(upper) local encoding = iif(upper, "UTF-8", "utf-8") - premake.w('', encoding) + p.w('', encoding) end @@ -381,17 +381,17 @@ end function _p(i, ...) if type(i) == "number" then _indentLevel = i - premake.w(...) + p.w(...) else _indentLevel = 0 - premake.w(i, ...) + p.w(i, ...) end end function _x(i, ...) local arg = {...} for i = 2, #arg do - arg[i] = premake.esc(arg[i]) + arg[i] = p.esc(arg[i]) end _p(i, unpack(arg)) end diff --git a/src/base/tools.lua b/src/base/tools.lua index f67292b3..65488bd5 100644 --- a/src/base/tools.lua +++ b/src/base/tools.lua @@ -16,7 +16,7 @@ -- @param identifier -- A toolset identifier composed of two parts: the toolset name, -- which should match of the name of the adapter object ("gcc", --- "clang", etc.) in the premake.tools namespace, and and optional +-- "clang", etc.) in the p.tools namespace, and and optional -- version number, separated by a dash. -- -- To make things more intuitive for Visual Studio users, supports diff --git a/src/base/tree.lua b/src/base/tree.lua index 8aaa5915..46e4b021 100644 --- a/src/base/tree.lua +++ b/src/base/tree.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2009-2013 Jason Perkins and the Premake project -- - premake.tree = {} - local tree = premake.tree + local p = premake + p.tree = {} + local tree = p.tree -- diff --git a/src/base/validation.lua b/src/base/validation.lua index 335cc26c..379c82fd 100644 --- a/src/base/validation.lua +++ b/src/base/validation.lua @@ -7,10 +7,9 @@ -- Copyright (c) 2002-2015 Jason Perkins and the Premake project --- - premake.validation = {} - local m = premake.validation - local p = premake + p.validation = {} + local m = p.validation m.elements = {} diff --git a/src/tools/clang.lua b/src/tools/clang.lua index 2928fcb5..ee6f20da 100644 --- a/src/tools/clang.lua +++ b/src/tools/clang.lua @@ -4,10 +4,11 @@ -- Copyright (c) 2013 Jason Perkins and the Premake project -- - premake.tools.clang = {} - local clang = premake.tools.clang - local gcc = premake.tools.gcc - local config = premake.config + local p = premake + p.tools.clang = {} + local clang = p.tools.clang + local gcc = p.tools.gcc + local config = p.config @@ -194,18 +195,18 @@ }, kind = { SharedLib = function(cfg) - local r = { iif(cfg.system == premake.MACOSX, "-dynamiclib", "-shared") } + local r = { iif(cfg.system == p.MACOSX, "-dynamiclib", "-shared") } if cfg.system == "windows" and not cfg.flags.NoImportLib then table.insert(r, '-Wl,--out-implib="' .. cfg.linktarget.relpath .. '"') - elseif cfg.system == premake.LINUX then - table.insert(r, '-Wl,-soname=' .. premake.quoted(cfg.linktarget.name)) - elseif cfg.system == premake.MACOSX then - table.insert(r, '-Wl,-install_name,' .. premake.quoted('@rpath/' .. cfg.linktarget.name)) + elseif cfg.system == p.LINUX then + table.insert(r, '-Wl,-soname=' .. p.quoted(cfg.linktarget.name)) + elseif cfg.system == p.MACOSX then + table.insert(r, '-Wl,-install_name,' .. p.quoted('@rpath/' .. cfg.linktarget.name)) end return r end, WindowedApp = function(cfg) - if cfg.system == premake.WINDOWS then return "-mwindows" end + if cfg.system == p.WINDOWS then return "-mwindows" end end, }, system = { diff --git a/src/tools/dotnet.lua b/src/tools/dotnet.lua index ffa02809..18b06ed1 100644 --- a/src/tools/dotnet.lua +++ b/src/tools/dotnet.lua @@ -5,10 +5,11 @@ -- - premake.tools.dotnet = {} - local dotnet = premake.tools.dotnet - local project = premake.project - local config = premake.config + local p = premake + p.tools.dotnet = {} + local dotnet = p.tools.dotnet + local project = p.project + local config = p.config -- @@ -50,7 +51,7 @@ info.action = "Resource" elseif ext == ".xaml" then if fcfg.buildaction == "Application" or path.getbasename(fname) == "App" then - if fcfg.project.kind == premake.SHAREDLIB then + if fcfg.project.kind == p.SHAREDLIB then info.action = "None" else info.action = "ApplicationDefinition" diff --git a/src/tools/gcc.lua b/src/tools/gcc.lua index 65159700..df8997f2 100644 --- a/src/tools/gcc.lua +++ b/src/tools/gcc.lua @@ -199,7 +199,7 @@ table.foreachi(cfg.forceincludes, function(value) local fn = project.getrelative(cfg.project, value) - table.insert(result, string.format('-include %s', premake.quoted(fn))) + table.insert(result, string.format('-include %s', p.quoted(fn))) end) return result @@ -214,11 +214,11 @@ local result = {} for _, dir in ipairs(dirs) do dir = project.getrelative(cfg.project, dir) - table.insert(result, '-I' .. premake.quoted(dir)) + table.insert(result, '-I' .. p.quoted(dir)) end for _, dir in ipairs(sysdirs or {}) do dir = project.getrelative(cfg.project, dir) - table.insert(result, '-isystem ' .. premake.quoted(dir)) + table.insert(result, '-isystem ' .. p.quoted(dir)) end return result end @@ -230,8 +230,8 @@ function gcc.getrunpathdirs(cfg, dirs) local result = {} - if not ((cfg.system == premake.MACOSX) - or (cfg.system == premake.LINUX)) then + if not ((cfg.system == p.MACOSX) + or (cfg.system == p.LINUX)) then return result end @@ -247,7 +247,7 @@ -- Automatically add linked shared libraries path relative to target directory for _, sibling in ipairs(config.getlinks(cfg, "siblings", "object")) do - if (sibling.kind == premake.SHAREDLIB) then + if (sibling.kind == p.SHAREDLIB) then local fullpath = sibling.linktarget.directory local rpath = path.getrelative(cfg.buildtarget.directory, fullpath) if not (table.contains(rpaths, rpath)) then @@ -257,9 +257,9 @@ end for _, rpath in ipairs(rpaths) do - if (cfg.system == premake.MACOSX) then + if (cfg.system == p.MACOSX) then rpath = "@loader_path/" .. rpath - elseif (cfg.system == premake.LINUX) then + elseif (cfg.system == p.LINUX) then rpath = iif(rpath == ".", "", "/" .. rpath) rpath = "$$ORIGIN" .. rpath end @@ -276,7 +276,7 @@ function gcc.ldsymbols(cfg) -- OS X has a bug, see http://lists.apple.com/archives/Darwin-dev/2006/Sep/msg00084.html - return iif(cfg.system == premake.MACOSX, "-Wl,-x", "-s") + return iif(cfg.system == p.MACOSX, "-Wl,-x", "-s") end gcc.ldflags = { @@ -289,18 +289,18 @@ }, kind = { SharedLib = function(cfg) - local r = { iif(cfg.system == premake.MACOSX, "-dynamiclib", "-shared") } - if cfg.system == premake.WINDOWS and not cfg.flags.NoImportLib then + local r = { iif(cfg.system == p.MACOSX, "-dynamiclib", "-shared") } + if cfg.system == p.WINDOWS and not cfg.flags.NoImportLib then table.insert(r, '-Wl,--out-implib="' .. cfg.linktarget.relpath .. '"') - elseif cfg.system == premake.LINUX then - table.insert(r, '-Wl,-soname=' .. premake.quoted(cfg.linktarget.name)) - elseif cfg.system == premake.MACOSX then - table.insert(r, '-Wl,-install_name,' .. premake.quoted('@rpath/' .. cfg.linktarget.name)) + elseif cfg.system == p.LINUX then + table.insert(r, '-Wl,-soname=' .. p.quoted(cfg.linktarget.name)) + elseif cfg.system == p.MACOSX then + table.insert(r, '-Wl,-install_name,' .. p.quoted('@rpath/' .. cfg.linktarget.name)) end return r end, WindowedApp = function(cfg) - if cfg.system == premake.WINDOWS then return "-mwindows" end + if cfg.system == p.WINDOWS then return "-mwindows" end end, }, system = { @@ -327,14 +327,14 @@ architecture = { x86 = function (cfg) local r = {} - if cfg.system ~= premake.MACOSX then + if cfg.system ~= p.MACOSX then table.insert (r, "-L/usr/lib32") end return r end, x86_64 = function (cfg) local r = {} - if cfg.system ~= premake.MACOSX then + if cfg.system ~= p.MACOSX then table.insert (r, "-L/usr/lib64") end return r @@ -352,12 +352,12 @@ -- paths, add those to the list of library search paths. The call -- config.getlinks() all includes cfg.libdirs. for _, dir in ipairs(config.getlinks(cfg, "system", "directory")) do - table.insert(flags, '-L' .. premake.quoted(dir)) + table.insert(flags, '-L' .. p.quoted(dir)) end if cfg.flags.RelativeLinks then for _, dir in ipairs(config.getlinks(cfg, "siblings", "directory")) do - local libFlag = "-L" .. premake.project.getrelative(cfg.project, dir) + local libFlag = "-L" .. p.project.getrelative(cfg.project, dir) if not table.contains(flags, libFlag) then table.insert(flags, libFlag) end @@ -365,7 +365,7 @@ end for _, dir in ipairs(cfg.syslibdirs) do - table.insert(flags, '-L' .. premake.quoted(dir)) + table.insert(flags, '-L' .. p.quoted(dir)) end return flags diff --git a/src/tools/msc.lua b/src/tools/msc.lua index cde83e29..b30158ed 100644 --- a/src/tools/msc.lua +++ b/src/tools/msc.lua @@ -189,7 +189,7 @@ table.foreachi(cfg.forceincludes, function(value) local fn = project.getrelative(cfg.project, value) - table.insert(result, "/FI" .. premake.quoted(fn)) + table.insert(result, "/FI" .. p.quoted(fn)) end) return result @@ -208,7 +208,7 @@ dirs = table.join(dirs, sysdirs) for _, dir in ipairs(dirs) do dir = project.getrelative(cfg.project, dir) - table.insert(result, '-I' .. premake.quoted(dir)) + table.insert(result, '-I' .. p.quoted(dir)) end return result end @@ -241,7 +241,7 @@ } function msc.getldflags(cfg) - local map = iif(cfg.kind ~= premake.STATICLIB, msc.linkerFlags, msc.librarianFlags) + local map = iif(cfg.kind ~= p.STATICLIB, msc.linkerFlags, msc.librarianFlags) local flags = config.mapFlags(cfg, map) table.insert(flags, 1, "/NOLOGO") diff --git a/tests/actions/make/cpp/test_clang.lua b/tests/actions/make/cpp/test_clang.lua index 27e851e9..3410b26a 100644 --- a/tests/actions/make/cpp/test_clang.lua +++ b/tests/actions/make/cpp/test_clang.lua @@ -4,10 +4,11 @@ -- Copyright (c) 2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_clang") - local make = premake.make - local cpp = premake.make.cpp - local project = premake.project + local make = p.make + local cpp = p.make.cpp + local project = p.project -- @@ -19,7 +20,7 @@ function suite.setup() wks = test.createWorkspace() toolset "clang" - prj = premake.workspace.getproject(wks, 1) + prj = p.workspace.getproject(wks, 1) end diff --git a/tests/actions/make/cpp/test_file_rules.lua b/tests/actions/make/cpp/test_file_rules.lua index 67ff9e48..17647d3f 100644 --- a/tests/actions/make/cpp/test_file_rules.lua +++ b/tests/actions/make/cpp/test_file_rules.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2009-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_cpp_file_rules") - local make = premake.make - local project = premake.project + local make = p.make + local project = p.project -- @@ -16,12 +17,12 @@ local wks, prj function suite.setup() - premake.escaper(make.esc) + p.escaper(make.esc) wks = test.createWorkspace() end local function prepare() - prj = premake.workspace.getproject(wks, 1) + prj = p.workspace.getproject(wks, 1) make.cppFileRules(prj) end diff --git a/tests/actions/make/cpp/test_flags.lua b/tests/actions/make/cpp/test_flags.lua index 6d16d7db..21f798f6 100644 --- a/tests/actions/make/cpp/test_flags.lua +++ b/tests/actions/make/cpp/test_flags.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2012-2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_flags") - local make = premake.make - local project = premake.project + local make = p.make + local project = p.project -- @@ -21,8 +22,8 @@ local function prepare(calls) local cfg = test.getconfig(prj, "Debug") - local toolset = premake.tools.gcc - premake.callarray(make, calls, cfg, toolset) + local toolset = p.tools.gcc + p.callarray(make, calls, cfg, toolset) end diff --git a/tests/actions/make/cpp/test_ldflags.lua b/tests/actions/make/cpp/test_ldflags.lua index a6cd8587..0007b68f 100644 --- a/tests/actions/make/cpp/test_ldflags.lua +++ b/tests/actions/make/cpp/test_ldflags.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2012-2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_ldflags") - local make = premake.make + local make = p.make -- @@ -21,7 +22,7 @@ local function prepare(calls) local cfg = test.getconfig(prj, "Debug") - local toolset = premake.tools.gcc + local toolset = p.tools.gcc make.ldFlags(cfg, toolset) end @@ -48,28 +49,28 @@ ALL_LDFLAGS += $(LDFLAGS) -L../libs -Llibs ]] end - + function suite.checkLibDirs_X86_64() architecture ("x86_64") - system (premake.LINUX) + system (p.LINUX) prepare() test.capture [[ ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib64 -m64 ]] end - + function suite.checkLibDirs_X86() architecture ("x86") - system (premake.LINUX) + system (p.LINUX) prepare() test.capture [[ ALL_LDFLAGS += $(LDFLAGS) -L/usr/lib32 -m32 ]] end - + function suite.checkLibDirs_X86_64_MacOSX() architecture ("x86_64") - system (premake.MACOSX) + system (p.MACOSX) prepare() test.capture [[ ALL_LDFLAGS += $(LDFLAGS) -m64 diff --git a/tests/actions/make/cpp/test_make_linking.lua b/tests/actions/make/cpp/test_make_linking.lua index 0b952638..4d13597e 100644 --- a/tests/actions/make/cpp/test_make_linking.lua +++ b/tests/actions/make/cpp/test_make_linking.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2010-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_linking") - local make = premake.make - local project = premake.project + local make = p.make + local project = p.project -- @@ -22,8 +23,8 @@ local function prepare(calls) local cfg = test.getconfig(prj, "Debug") - local toolset = premake.tools.gcc - premake.callarray(make, calls, cfg, toolset) + local toolset = p.tools.gcc + p.callarray(make, calls, cfg, toolset) end diff --git a/tests/actions/make/cpp/test_make_pch.lua b/tests/actions/make/cpp/test_make_pch.lua index c807b790..9b374f06 100644 --- a/tests/actions/make/cpp/test_make_pch.lua +++ b/tests/actions/make/cpp/test_make_pch.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2010-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_pch") - local make = premake.make - local project = premake.project + local make = p.make + local project = p.project diff --git a/tests/actions/make/cpp/test_target_rules.lua b/tests/actions/make/cpp/test_target_rules.lua index e3a586b4..f8fb3cc0 100644 --- a/tests/actions/make/cpp/test_target_rules.lua +++ b/tests/actions/make/cpp/test_target_rules.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2009-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_cpp_target_rules") - local make = premake.make - local project = premake.project + local make = p.make + local project = p.project -- diff --git a/tests/actions/make/cpp/test_tools.lua b/tests/actions/make/cpp/test_tools.lua index 8b234acc..80ebd4f6 100644 --- a/tests/actions/make/cpp/test_tools.lua +++ b/tests/actions/make/cpp/test_tools.lua @@ -4,10 +4,11 @@ -- Copyright (c) 2012-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_tools") - local make = premake.make - local cpp = premake.make.cpp - local project = premake.project + local make = p.make + local cpp = p.make.cpp + local project = p.project -- @@ -27,7 +28,7 @@ -- function suite.usesCorrectTools() - make.cppTools(cfg, premake.tools.gcc) + make.cppTools(cfg, p.tools.gcc) test.capture [[ RESCOMP = windres ]] diff --git a/tests/actions/make/cpp/test_wiidev.lua b/tests/actions/make/cpp/test_wiidev.lua index 4294ba8b..54a6113e 100644 --- a/tests/actions/make/cpp/test_wiidev.lua +++ b/tests/actions/make/cpp/test_wiidev.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2011-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_wiidev") - local make = premake.make - local project = premake.project + local make = p.make + local project = p.project -- @@ -28,14 +29,14 @@ -- function suite.writesCorrectCppFlags() - make.cppFlags(cfg, premake.tools.gcc) + make.cppFlags(cfg, p.tools.gcc) test.capture [[ ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP -I$(LIBOGC_INC) $(MACHDEP) $(DEFINES) $(INCLUDES) ]] end function suite.writesCorrectLinkerFlags() - make.ldFlags(cfg, premake.tools.gcc) + make.ldFlags(cfg, p.tools.gcc) test.capture [[ ALL_LDFLAGS += $(LDFLAGS) -L$(LIBOGC_LIB) $(MACHDEP) ]] @@ -47,7 +48,7 @@ -- function suite.writesIncludeBlock() - make.settings(cfg, premake.tools.gcc) + make.settings(cfg, p.tools.gcc) test.capture [[ ifeq ($(strip $(DEVKITPPC)),) $(error "DEVKITPPC environment variable is not set")' diff --git a/tests/actions/make/cs/test_embed_files.lua b/tests/actions/make/cs/test_embed_files.lua index 1a0d759d..36b8d141 100644 --- a/tests/actions/make/cs/test_embed_files.lua +++ b/tests/actions/make/cs/test_embed_files.lua @@ -4,10 +4,11 @@ -- Copyright (c) 2013-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_cs_embed_files") - local make = premake.make - local cs = premake.make.cs - local project = premake.project + local make = p.make + local cs = p.make.cs + local project = p.project -- @@ -21,8 +22,8 @@ end local function prepare() - prj = premake.workspace.getproject(wks, 1) - make.csEmbedFiles(prj, premake.tools.dotnet) + prj = p.workspace.getproject(wks, 1) + make.csEmbedFiles(prj, p.tools.dotnet) end diff --git a/tests/actions/make/cs/test_flags.lua b/tests/actions/make/cs/test_flags.lua index 40d028b2..ac22a2c3 100644 --- a/tests/actions/make/cs/test_flags.lua +++ b/tests/actions/make/cs/test_flags.lua @@ -4,10 +4,11 @@ -- Copyright (c) 2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_cs_flags") - local make = premake.make - local cs = premake.make.cs - local project = premake.project + local make = p.make + local cs = p.make.cs + local project = p.project -- @@ -22,7 +23,7 @@ local function prepare() local cfg = test.getconfig(prj, "Debug") - make.csFlags(cfg, premake.tools.dotnet) + make.csFlags(cfg, p.tools.dotnet) end diff --git a/tests/actions/make/cs/test_links.lua b/tests/actions/make/cs/test_links.lua index 82ef9ba0..6116eb40 100644 --- a/tests/actions/make/cs/test_links.lua +++ b/tests/actions/make/cs/test_links.lua @@ -4,10 +4,11 @@ -- Copyright (c) 2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_cs_links") - local make = premake.make - local cs = premake.make.cs - local project = premake.project + local make = p.make + local cs = p.make.cs + local project = p.project -- -- Setup @@ -21,7 +22,7 @@ local function prepare() local cfg = test.getconfig(prj, "Debug") - make.csLinkCmd(cfg, premake.tools.dotnet) + make.csLinkCmd(cfg, p.tools.dotnet) end diff --git a/tests/actions/make/cs/test_response.lua b/tests/actions/make/cs/test_response.lua index d766d45a..5ffed6a8 100644 --- a/tests/actions/make/cs/test_response.lua +++ b/tests/actions/make/cs/test_response.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2009-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_cs_response") - local make = premake.make + local make = p.make -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks = test.createWorkspace() end diff --git a/tests/actions/make/cs/test_sources.lua b/tests/actions/make/cs/test_sources.lua index 60ec08bd..0789c6c9 100644 --- a/tests/actions/make/cs/test_sources.lua +++ b/tests/actions/make/cs/test_sources.lua @@ -4,10 +4,11 @@ -- Copyright (c) 2013-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_cs_sources") - local make = premake.make - local cs = premake.make.cs - local project = premake.project + local make = p.make + local cs = p.make.cs + local project = p.project -- @@ -21,8 +22,8 @@ end local function prepare() - prj = premake.workspace.getproject(wks, 1) - make.csSources(prj, premake.tools.dotnet) + prj = p.workspace.getproject(wks, 1) + make.csSources(prj, p.tools.dotnet) end diff --git a/tests/actions/make/test_make_escaping.lua b/tests/actions/make/test_make_escaping.lua index a1ad1937..fa24937f 100644 --- a/tests/actions/make/test_make_escaping.lua +++ b/tests/actions/make/test_make_escaping.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2010-2012 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_escaping") - local make = premake.make + local make = p.make function suite.Escapes_Spaces() diff --git a/tests/actions/make/test_make_tovar.lua b/tests/actions/make/test_make_tovar.lua index b4b1832a..0c73474e 100644 --- a/tests/actions/make/test_make_tovar.lua +++ b/tests/actions/make/test_make_tovar.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2012 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_tovar") - local make = premake.make + local make = p.make -- diff --git a/tests/actions/make/workspace/test_config_maps.lua b/tests/actions/make/workspace/test_config_maps.lua index 5f71ff96..38506239 100644 --- a/tests/actions/make/workspace/test_config_maps.lua +++ b/tests/actions/make/workspace/test_config_maps.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2012 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_config_maps") - local make = premake.make + local make = p.make -- diff --git a/tests/actions/make/workspace/test_group_rule.lua b/tests/actions/make/workspace/test_group_rule.lua index 16000841..aebb3f82 100644 --- a/tests/actions/make/workspace/test_group_rule.lua +++ b/tests/actions/make/workspace/test_group_rule.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2012-2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_group_rule") - local make = premake.make + local make = p.make -- diff --git a/tests/actions/make/workspace/test_help_rule.lua b/tests/actions/make/workspace/test_help_rule.lua index a4be6fc4..3e3ab50a 100644 --- a/tests/actions/make/workspace/test_help_rule.lua +++ b/tests/actions/make/workspace/test_help_rule.lua @@ -4,6 +4,7 @@ -- Copyright (c) 2012-2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_help_rule") @@ -19,7 +20,7 @@ local function prepare() wks = test.getWorkspace(wks) - premake.make.helprule(wks) + p.make.helprule(wks) end diff --git a/tests/actions/make/workspace/test_project_rule.lua b/tests/actions/make/workspace/test_project_rule.lua index 3fd94dd7..3615bd2a 100644 --- a/tests/actions/make/workspace/test_project_rule.lua +++ b/tests/actions/make/workspace/test_project_rule.lua @@ -4,6 +4,7 @@ -- Copyright (c) 2012-2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("make_project_rule") @@ -18,9 +19,9 @@ end local function prepare() - premake.oven.bake() + p.oven.bake() wks = test.getWorkspace(wks) - premake.make.projectrules(wks) + p.make.projectrules(wks) end diff --git a/tests/actions/vstudio/cs2005/projectelement.lua b/tests/actions/vstudio/cs2005/projectelement.lua index df216aca..ec640fde 100755 --- a/tests/actions/vstudio/cs2005/projectelement.lua +++ b/tests/actions/vstudio/cs2005/projectelement.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2009-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_cs2005_projectelement") - local cs2005 = premake.vstudio.cs2005 + local cs2005 = p.vstudio.cs2005 -- @@ -29,7 +30,7 @@ -- function suite.on2005() - premake.action.set("vs2005") + p.action.set("vs2005") prepare() test.capture [[ @@ -38,7 +39,7 @@ function suite.on2008() - premake.action.set("vs2008") + p.action.set("vs2008") prepare() test.capture [[ @@ -47,7 +48,7 @@ function suite.on2010() - premake.action.set("vs2010") + p.action.set("vs2010") prepare() test.capture [[ @@ -57,7 +58,7 @@ function suite.on2012() - premake.action.set("vs2012") + p.action.set("vs2012") prepare() test.capture [[ @@ -67,7 +68,7 @@ function suite.on2013() - premake.action.set("vs2013") + p.action.set("vs2013") prepare() test.capture [[ diff --git a/tests/actions/vstudio/cs2005/projectsettings.lua b/tests/actions/vstudio/cs2005/projectsettings.lua index b52b0d87..25a4397b 100755 --- a/tests/actions/vstudio/cs2005/projectsettings.lua +++ b/tests/actions/vstudio/cs2005/projectsettings.lua @@ -4,9 +4,9 @@ -- Copyright (c) 2009-2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_cs2005_projectsettings") - - local cs2005 = premake.vstudio.cs2005 + local cs2005 = p.vstudio.cs2005 -- @@ -16,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2005") + p.action.set("vs2005") wks = test.createWorkspace() language "C#" uuid "AE61726D-187C-E440-BD07-2556188A6565" @@ -51,7 +51,7 @@ function suite.OnVs2008() - premake.action.set("vs2008") + p.action.set("vs2008") prepare() test.capture [[ @@ -70,7 +70,7 @@ function suite.OnVs2010() - premake.action.set("vs2010") + p.action.set("vs2010") prepare() test.capture [[ @@ -93,7 +93,7 @@ function suite.onVs2012() - premake.action.set("vs2012") + p.action.set("vs2012") prepare() test.capture [[ @@ -183,7 +183,7 @@ -- function suite.projectTypeGuids_onWPF() - premake.action.set("vs2010") + p.action.set("vs2010") flags { "WPF" } prepare() test.capture [[ diff --git a/tests/actions/vstudio/cs2005/test_assembly_refs.lua b/tests/actions/vstudio/cs2005/test_assembly_refs.lua index 6a68ceaa..f4bb5189 100644 --- a/tests/actions/vstudio/cs2005/test_assembly_refs.lua +++ b/tests/actions/vstudio/cs2005/test_assembly_refs.lua @@ -4,9 +4,9 @@ -- Copyright (c) 2012-2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_cs2005_assembly_refs") - - local cs2005 = premake.vstudio.cs2005 + local cs2005 = p.vstudio.cs2005 -- @@ -16,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks = test.createWorkspace() language "C#" end diff --git a/tests/actions/vstudio/cs2005/test_build_events.lua b/tests/actions/vstudio/cs2005/test_build_events.lua index 5f626ec1..52223ae5 100644 --- a/tests/actions/vstudio/cs2005/test_build_events.lua +++ b/tests/actions/vstudio/cs2005/test_build_events.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2012-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_cs2005_build_events") - local cs2005 = premake.vstudio.cs2005 + local cs2005 = p.vstudio.cs2005 -- @@ -15,8 +16,8 @@ local wks, prj, cfg function suite.setup() - premake.action.set("vs2005") - premake.escaper(premake.vstudio.vs2010.esc) + p.action.set("vs2005") + p.escaper(p.vstudio.vs2010.esc) wks = test.createWorkspace() end diff --git a/tests/actions/vstudio/cs2005/test_common_props.lua b/tests/actions/vstudio/cs2005/test_common_props.lua index 18783398..1c5d9751 100644 --- a/tests/actions/vstudio/cs2005/test_common_props.lua +++ b/tests/actions/vstudio/cs2005/test_common_props.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs2012_csproj_common_props") - local cs2005 = premake.vstudio.cs2005 + local cs2005 = p.vstudio.cs2005 -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2012") + p.action.set("vs2012") wks = test.createWorkspace() language "C#" end diff --git a/tests/actions/vstudio/cs2005/test_compiler_props.lua b/tests/actions/vstudio/cs2005/test_compiler_props.lua index dfd3323e..075ea1ef 100644 --- a/tests/actions/vstudio/cs2005/test_compiler_props.lua +++ b/tests/actions/vstudio/cs2005/test_compiler_props.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2012-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_cs2005_compiler_props") - local cs2005 = premake.vstudio.cs2005 - local project = premake.project + local cs2005 = p.vstudio.cs2005 + local project = p.project -- @@ -16,7 +17,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2005") + p.action.set("vs2005") wks, prj = test.createWorkspace() end diff --git a/tests/actions/vstudio/cs2005/test_debug_props.lua b/tests/actions/vstudio/cs2005/test_debug_props.lua index 917ecbf4..7a5ca240 100644 --- a/tests/actions/vstudio/cs2005/test_debug_props.lua +++ b/tests/actions/vstudio/cs2005/test_debug_props.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2012-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_cs2005_debug_props") - local cs2005 = premake.vstudio.cs2005 - local project = premake.project + local cs2005 = p.vstudio.cs2005 + local project = p.project -- @@ -16,7 +17,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2005") + p.action.set("vs2005") wks, prj = test.createWorkspace() end diff --git a/tests/actions/vstudio/cs2005/test_files.lua b/tests/actions/vstudio/cs2005/test_files.lua index 6586da4c..4e5d5176 100755 --- a/tests/actions/vstudio/cs2005/test_files.lua +++ b/tests/actions/vstudio/cs2005/test_files.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2009-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_cs2005_files") - local cs2005 = premake.vstudio.cs2005 + local cs2005 = p.vstudio.cs2005 -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2005") + p.action.set("vs2005") wks = test.createWorkspace() end diff --git a/tests/actions/vstudio/cs2005/test_icon.lua b/tests/actions/vstudio/cs2005/test_icon.lua index 778d6146..b41f30fd 100644 --- a/tests/actions/vstudio/cs2005/test_icon.lua +++ b/tests/actions/vstudio/cs2005/test_icon.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_cs2005_icon") - local cs2005 = premake.vstudio.cs2005 + local cs2005 = p.vstudio.cs2005 -- diff --git a/tests/actions/vstudio/cs2005/test_nuget_config.lua b/tests/actions/vstudio/cs2005/test_nuget_config.lua index 88a48099..8be35526 100644 --- a/tests/actions/vstudio/cs2005/test_nuget_config.lua +++ b/tests/actions/vstudio/cs2005/test_nuget_config.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2017 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_cs2005_nuget_config") - local cs2005 = premake.vstudio.cs2005 - local nuget2010 = premake.vstudio.nuget2010 + local cs2005 = p.vstudio.cs2005 + local nuget2010 = p.vstudio.nuget2010 -- @@ -16,7 +17,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks = test.createWorkspace() language "C#" end diff --git a/tests/actions/vstudio/cs2005/test_nuget_packages_config.lua b/tests/actions/vstudio/cs2005/test_nuget_packages_config.lua index 65a16961..0247c569 100644 --- a/tests/actions/vstudio/cs2005/test_nuget_packages_config.lua +++ b/tests/actions/vstudio/cs2005/test_nuget_packages_config.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2012-2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_cs2005_nuget_packages_config") - local cs2005 = premake.vstudio.cs2005 - local nuget2010 = premake.vstudio.nuget2010 + local cs2005 = p.vstudio.cs2005 + local nuget2010 = p.vstudio.nuget2010 -- @@ -16,7 +17,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks = test.createWorkspace() language "C#" end diff --git a/tests/actions/vstudio/cs2005/test_output_props.lua b/tests/actions/vstudio/cs2005/test_output_props.lua index a0324e15..3ac0f8e7 100644 --- a/tests/actions/vstudio/cs2005/test_output_props.lua +++ b/tests/actions/vstudio/cs2005/test_output_props.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2012-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_cs2005_output_props") - local cs2005 = premake.vstudio.cs2005 - local project = premake.project + local cs2005 = p.vstudio.cs2005 + local project = p.project -- @@ -16,7 +17,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2005") + p.action.set("vs2005") wks, prj = test.createWorkspace() language "C#" end @@ -45,7 +46,7 @@ -- function suite.intermediateDirectory_onVs2008() - premake.action.set("vs2008") + p.action.set("vs2008") prepare() test.capture [[ bin\Debug\ @@ -54,7 +55,7 @@ end function suite.intermediateDirectory_onVs2010() - premake.action.set("vs2010") + p.action.set("vs2010") prepare() test.capture [[ bin\Debug\ diff --git a/tests/actions/vstudio/cs2005/test_platform_groups.lua b/tests/actions/vstudio/cs2005/test_platform_groups.lua index 733f9182..51fdedb8 100644 --- a/tests/actions/vstudio/cs2005/test_platform_groups.lua +++ b/tests/actions/vstudio/cs2005/test_platform_groups.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2009-2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_cs2005_platform_groups") - local cs2005 = premake.vstudio.cs2005 + local cs2005 = p.vstudio.cs2005 -- -- Setup @@ -14,7 +15,7 @@ local wks function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks = workspace("MyWorkspace") configurations { "Debug", "Release" } language "C#" @@ -32,7 +33,7 @@ -- function suite.vs2008() - premake.action.set("vs2008") + p.action.set("vs2008") prepare() test.capture [[ @@ -41,7 +42,7 @@ function suite.vs2010() - premake.action.set("vs2010") + p.action.set("vs2010") prepare() test.capture [[ @@ -55,7 +56,7 @@ -- function suite.vs2008_onAnyCpu() - premake.action.set("vs2008") + p.action.set("vs2008") platforms "Any CPU" prepare("Any CPU") test.capture [[ @@ -65,7 +66,7 @@ function suite.vs2010_onAnyCpu() - premake.action.set("vs2010") + p.action.set("vs2010") platforms "Any CPU" prepare("Any CPU") test.capture [[ diff --git a/tests/actions/vstudio/cs2005/test_project_refs.lua b/tests/actions/vstudio/cs2005/test_project_refs.lua index 1b2a8311..687ecb27 100644 --- a/tests/actions/vstudio/cs2005/test_project_refs.lua +++ b/tests/actions/vstudio/cs2005/test_project_refs.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2012 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_cs2005_project_refs") - local cs2005 = premake.vstudio.cs2005 + local cs2005 = p.vstudio.cs2005 -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2008") + p.action.set("vs2008") wks = test.createWorkspace() uuid "00112233-4455-6677-8888-99AABBCCDDEE" test.createproject(wks) diff --git a/tests/actions/vstudio/cs2005/test_targets.lua b/tests/actions/vstudio/cs2005/test_targets.lua index 0e06c698..4e0b3300 100644 --- a/tests/actions/vstudio/cs2005/test_targets.lua +++ b/tests/actions/vstudio/cs2005/test_targets.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs2012_csproj_targets") - local cs2005 = premake.vstudio.cs2005 + local cs2005 = p.vstudio.cs2005 -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2012") + p.action.set("vs2012") wks = test.createWorkspace() language "C#" end diff --git a/tests/actions/vstudio/cs2005/test_user_file.lua b/tests/actions/vstudio/cs2005/test_user_file.lua index cbebe606..97f16b8d 100644 --- a/tests/actions/vstudio/cs2005/test_user_file.lua +++ b/tests/actions/vstudio/cs2005/test_user_file.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_cs2005_user_file") - local cs2005 = premake.vstudio.cs2005 + local cs2005 = p.vstudio.cs2005 -- @@ -15,7 +16,7 @@ local wks function suite.setup() - premake.action.set("vs2008") + p.action.set("vs2008") wks = test.createWorkspace() language "C#" end diff --git a/tests/actions/vstudio/sln2005/test_dependencies.lua b/tests/actions/vstudio/sln2005/test_dependencies.lua index 67960a72..6d2e585f 100755 --- a/tests/actions/vstudio/sln2005/test_dependencies.lua +++ b/tests/actions/vstudio/sln2005/test_dependencies.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2009-2012 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_sln2005_dependencies") - local sln2005 = premake.vstudio.sln2005 + local sln2005 = p.vstudio.sln2005 -- @@ -15,7 +16,7 @@ local wks, prj1, prj2 function suite.setup() - premake.action.set("vs2005") + p.action.set("vs2005") wks, prj1 = test.createWorkspace() uuid "AE61726D-187C-E440-BD07-2556188A6565" prj2 = test.createproject(wks) @@ -70,7 +71,7 @@ EndProjectSection -- function suite.dependency_onCSharpProjectsVs2010() - premake.action.set("vs2010") + p.action.set("vs2010") prepare("C#") test.capture [[ ProjectSection(ProjectDependencies) = postProject @@ -86,7 +87,7 @@ EndProjectSection -- function suite.dependency_onCSharpProjectsVs2012() - premake.action.set("vs2012") + p.action.set("vs2012") prepare("C#") test.capture [[ ProjectSection(ProjectDependencies) = postProject diff --git a/tests/actions/vstudio/sln2005/test_header.lua b/tests/actions/vstudio/sln2005/test_header.lua index 69118f90..117b6f3c 100755 --- a/tests/actions/vstudio/sln2005/test_header.lua +++ b/tests/actions/vstudio/sln2005/test_header.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2009-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_sln2005_header") - local sln2005 = premake.vstudio.sln2005 + local sln2005 = p.vstudio.sln2005 -- @@ -28,7 +29,7 @@ -- function suite.on2005() - premake.action.set("vs2005") + p.action.set("vs2005") prepare() test.capture [[ Microsoft Visual Studio Solution File, Format Version 9.00 @@ -38,7 +39,7 @@ Microsoft Visual Studio Solution File, Format Version 9.00 function suite.on2008() - premake.action.set("vs2008") + p.action.set("vs2008") prepare() test.capture [[ Microsoft Visual Studio Solution File, Format Version 10.00 @@ -48,7 +49,7 @@ Microsoft Visual Studio Solution File, Format Version 10.00 function suite.on2010() - premake.action.set("vs2010") + p.action.set("vs2010") prepare() test.capture [[ Microsoft Visual Studio Solution File, Format Version 11.00 @@ -58,7 +59,7 @@ Microsoft Visual Studio Solution File, Format Version 11.00 function suite.on2012() - premake.action.set("vs2012") + p.action.set("vs2012") prepare() test.capture [[ Microsoft Visual Studio Solution File, Format Version 12.00 @@ -68,7 +69,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 function suite.on2013() - premake.action.set("vs2013") + p.action.set("vs2013") prepare() test.capture [[ Microsoft Visual Studio Solution File, Format Version 12.00 diff --git a/tests/actions/vstudio/sln2005/test_nested_projects.lua b/tests/actions/vstudio/sln2005/test_nested_projects.lua index 2026dcd3..e8dc9920 100644 --- a/tests/actions/vstudio/sln2005/test_nested_projects.lua +++ b/tests/actions/vstudio/sln2005/test_nested_projects.lua @@ -4,9 +4,9 @@ -- Copyright (c) 2012-2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_sln2005_nested_projects") - - local sln2005 = premake.vstudio.sln2005 + local sln2005 = p.vstudio.sln2005 -- @@ -16,7 +16,7 @@ local wks function suite.setup() - premake.action.set("vs2008") + p.action.set("vs2008") wks = workspace("MyWorkspace") configurations { "Debug", "Release" } language "C++" diff --git a/tests/actions/vstudio/sln2005/test_platforms.lua b/tests/actions/vstudio/sln2005/test_platforms.lua index a58e95fc..5e3d7d21 100644 --- a/tests/actions/vstudio/sln2005/test_platforms.lua +++ b/tests/actions/vstudio/sln2005/test_platforms.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2009-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_sln2005_platforms") - local sln2005 = premake.vstudio.sln2005 + local sln2005 = p.vstudio.sln2005 -- @@ -15,7 +16,7 @@ local wks function suite.setup() - premake.action.set("vs2008") + p.action.set("vs2008") wks = workspace("MyWorkspace") configurations { "Debug", "Release" } language "C++" diff --git a/tests/actions/vstudio/sln2005/test_projects.lua b/tests/actions/vstudio/sln2005/test_projects.lua index 54aea72b..1ce5cae2 100755 --- a/tests/actions/vstudio/sln2005/test_projects.lua +++ b/tests/actions/vstudio/sln2005/test_projects.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2009-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_sln2005_projects") - local sln2005 = premake.vstudio.sln2005 + local sln2005 = p.vstudio.sln2005 -- @@ -15,8 +16,8 @@ local wks function suite.setup() - premake.action.set("vs2005") - premake.escaper(premake.vstudio.vs2005.esc) + p.action.set("vs2005") + p.escaper(p.vstudio.vs2005.esc) wks = workspace("MyWorkspace") configurations { "Debug", "Release" } language "C++" diff --git a/tests/actions/vstudio/sln2005/test_sections.lua b/tests/actions/vstudio/sln2005/test_sections.lua index 5b244a0b..9f2f2f37 100644 --- a/tests/actions/vstudio/sln2005/test_sections.lua +++ b/tests/actions/vstudio/sln2005/test_sections.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2009-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_sln2005_sections") - local sln2005 = premake.vstudio.sln2005 + local sln2005 = p.vstudio.sln2005 -- @@ -17,7 +18,7 @@ function suite.setup() _MAIN_SCRIPT = "c:\\test\\premake5.lua" - premake.escaper(premake.vstudio.vs2005.esc) + p.escaper(p.vstudio.vs2005.esc) wks = workspace("MyWorkspace") wks.location = "c:\\test\\build" @@ -46,7 +47,7 @@ GlobalSection(ExtensibilityGlobals) = postSolution project "MyProject" sln2005.extensibilityGlobals(wks) - local res = premake.captured() + local res = p.captured() if (#res > 0) then test.fail("no editorintegration output was expected"); end diff --git a/tests/actions/vstudio/vc200x/test_assembly_refs.lua b/tests/actions/vstudio/vc200x/test_assembly_refs.lua index 7d6e6d9a..957e0160 100644 --- a/tests/actions/vstudio/vc200x/test_assembly_refs.lua +++ b/tests/actions/vstudio/vc200x/test_assembly_refs.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs200x_assembly_refs") - local vc200x = premake.vstudio.vc200x + local vc200x = p.vstudio.vc200x -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2005") + p.action.set("vs2005") wks = test.createWorkspace() clr "On" end diff --git a/tests/actions/vstudio/vc200x/test_build_steps.lua b/tests/actions/vstudio/vc200x/test_build_steps.lua index 2285ad41..69ee1ac2 100644 --- a/tests/actions/vstudio/vc200x/test_build_steps.lua +++ b/tests/actions/vstudio/vc200x/test_build_steps.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs200x_build_steps") - local vc200x = premake.vstudio.vc200x + local vc200x = p.vstudio.vc200x -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.escaper(premake.vstudio.vs2005.esc) + p.escaper(p.vstudio.vs2005.esc) wks, prj = test.createWorkspace() end diff --git a/tests/actions/vstudio/vc200x/test_compiler_block.lua b/tests/actions/vstudio/vc200x/test_compiler_block.lua index 2fee6b2d..e409f51b 100644 --- a/tests/actions/vstudio/vc200x/test_compiler_block.lua +++ b/tests/actions/vstudio/vc200x/test_compiler_block.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2011-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs200x_compiler_block") - local vc200x = premake.vstudio.vc200x + local vc200x = p.vstudio.vc200x -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2008") + p.action.set("vs2008") wks, prj = test.createWorkspace() end @@ -383,7 +384,7 @@ -- function suite._64BitPortabilityOn_onVS2005() - premake.action.set("vs2005") + p.action.set("vs2005") prepare() test.capture [[ " } prepare() test.capture [[ @@ -284,7 +285,7 @@ Level3 &;<;>;%(PreprocessorDefinitions) ]] - premake.escaper(nil) + p.escaper(nil) end @@ -561,7 +562,7 @@ function suite.exceptions_onNoExceptionsVS2013() exceptionhandling "Off" - premake.action.set("vs2013") + p.action.set("vs2013") prepare() test.capture [[ @@ -836,7 +837,7 @@ -- function suite.onNoSymbolsVS2015() symbols 'Off' - premake.action.set("vs2015") + p.action.set("vs2015") prepare() test.capture [[ diff --git a/tests/actions/vstudio/vc2010/test_config_props.lua b/tests/actions/vstudio/vc2010/test_config_props.lua index 7d702dc9..64dd68be 100755 --- a/tests/actions/vstudio/vc2010/test_config_props.lua +++ b/tests/actions/vstudio/vc2010/test_config_props.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2011-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_vs2010_config_props") - local vc2010 = premake.vstudio.vc2010 - local project = premake.project + local vc2010 = p.vstudio.vc2010 + local project = p.project -- @@ -16,7 +17,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks, prj = test.createWorkspace() end diff --git a/tests/actions/vstudio/vc2010/test_debug_settings.lua b/tests/actions/vstudio/vc2010/test_debug_settings.lua index 3c268c60..e43c09ff 100755 --- a/tests/actions/vstudio/vc2010/test_debug_settings.lua +++ b/tests/actions/vstudio/vc2010/test_debug_settings.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2011-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_vs2010_debug_settings") - local vc2010 = premake.vstudio.vc2010 - local project = premake.project + local vc2010 = p.vstudio.vc2010 + local project = p.project -- @@ -16,7 +17,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks, prj = test.createWorkspace() end diff --git a/tests/actions/vstudio/vc2010/test_ensure_nuget_imports.lua b/tests/actions/vstudio/vc2010/test_ensure_nuget_imports.lua index d691a92d..9c3ce54e 100644 --- a/tests/actions/vstudio/vc2010/test_ensure_nuget_imports.lua +++ b/tests/actions/vstudio/vc2010/test_ensure_nuget_imports.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2016 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs2010_ensure_nuget_imports") - local vc2010 = premake.vstudio.vc2010 - local project = premake.project + local vc2010 = p.vstudio.vc2010 + local project = p.project -- @@ -16,12 +17,12 @@ local wks function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks = test.createWorkspace() end local function prepare() - local prj = premake.solution.getproject(wks, 1) + local prj = p.solution.getproject(wks, 1) vc2010.ensureNuGetPackageBuildImports(prj) end diff --git a/tests/actions/vstudio/vc2010/test_excluded_configs.lua b/tests/actions/vstudio/vc2010/test_excluded_configs.lua index cdb28d21..34fa07a7 100644 --- a/tests/actions/vstudio/vc2010/test_excluded_configs.lua +++ b/tests/actions/vstudio/vc2010/test_excluded_configs.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2012-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs2010_excluded_configs") - local vc2010 = premake.vstudio.vc2010 + local vc2010 = p.vstudio.vc2010 -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks = workspace("MyWorkspace") configurations { "Debug", "Release" } diff --git a/tests/actions/vstudio/vc2010/test_extension_settings.lua b/tests/actions/vstudio/vc2010/test_extension_settings.lua index 01059b3c..e52120c0 100644 --- a/tests/actions/vstudio/vc2010/test_extension_settings.lua +++ b/tests/actions/vstudio/vc2010/test_extension_settings.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs2010_extension_settings") - local vc2010 = premake.vstudio.vc2010 - local project = premake.project + local vc2010 = p.vstudio.vc2010 + local project = p.project -- @@ -16,7 +17,7 @@ local wks function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") rule "MyRules" rule "MyOtherRules" wks = test.createWorkspace() diff --git a/tests/actions/vstudio/vc2010/test_extension_targets.lua b/tests/actions/vstudio/vc2010/test_extension_targets.lua index 5575a2b5..1503cf40 100644 --- a/tests/actions/vstudio/vc2010/test_extension_targets.lua +++ b/tests/actions/vstudio/vc2010/test_extension_targets.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs2010_extension_targets") - local vc2010 = premake.vstudio.vc2010 - local project = premake.project + local vc2010 = p.vstudio.vc2010 + local project = p.project -- @@ -16,7 +17,7 @@ local wks function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") rule "MyRules" rule "MyOtherRules" wks = test.createWorkspace() diff --git a/tests/actions/vstudio/vc2010/test_files.lua b/tests/actions/vstudio/vc2010/test_files.lua index 6775cbf8..26375b33 100755 --- a/tests/actions/vstudio/vc2010/test_files.lua +++ b/tests/actions/vstudio/vc2010/test_files.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2011-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_vs2010_files") - local vc2010 = premake.vstudio.vc2010 + local vc2010 = p.vstudio.vc2010 -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") rule "Animation" fileextension ".dae" diff --git a/tests/actions/vstudio/vc2010/test_filter_ids.lua b/tests/actions/vstudio/vc2010/test_filter_ids.lua index e28e2952..e256de96 100644 --- a/tests/actions/vstudio/vc2010/test_filter_ids.lua +++ b/tests/actions/vstudio/vc2010/test_filter_ids.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2011-2012 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs2010_filter_ids") - local vc2010 = premake.vstudio.vc2010 + local vc2010 = p.vstudio.vc2010 -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks = test.createWorkspace() end diff --git a/tests/actions/vstudio/vc2010/test_filters.lua b/tests/actions/vstudio/vc2010/test_filters.lua index 9c69b62b..d895412c 100644 --- a/tests/actions/vstudio/vc2010/test_filters.lua +++ b/tests/actions/vstudio/vc2010/test_filters.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2011-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs2010_filters") - local vc2010 = premake.vstudio.vc2010 + local vc2010 = p.vstudio.vc2010 -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks = test.createWorkspace() end diff --git a/tests/actions/vstudio/vc2010/test_floatingpoint.lua b/tests/actions/vstudio/vc2010/test_floatingpoint.lua index 1816ff24..4a402dd0 100644 --- a/tests/actions/vstudio/vc2010/test_floatingpoint.lua +++ b/tests/actions/vstudio/vc2010/test_floatingpoint.lua @@ -6,14 +6,15 @@ -- Copyright (c) 2015 Jason Perkins and the Premake project --- + local p = premake local suite = test.declare("vs2010_vc_floatingpoint") - local m = premake.vstudio.vc2010 + local m = p.vstudio.vc2010 local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks, prj = test.createWorkspace() end diff --git a/tests/actions/vstudio/vc2010/test_globals.lua b/tests/actions/vstudio/vc2010/test_globals.lua index dccee468..898a15a6 100755 --- a/tests/actions/vstudio/vc2010/test_globals.lua +++ b/tests/actions/vstudio/vc2010/test_globals.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2011-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_vs2010_globals") - local vc2010 = premake.vstudio.vc2010 + local vc2010 = p.vstudio.vc2010 -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks = test.createWorkspace() end @@ -78,7 +79,7 @@ end function suite.frameworkVersionIsCorrect_on2013() - premake.action.set("vs2013") + p.action.set("vs2013") clr "On" prepare() test.capture [[ @@ -180,7 +181,7 @@ -- function suite.structureIsCorrect_on2013() - premake.action.set("vs2013") + p.action.set("vs2013") prepare() test.capture [[ diff --git a/tests/actions/vstudio/vc2010/test_header.lua b/tests/actions/vstudio/vc2010/test_header.lua index bbd93602..58f901bc 100644 --- a/tests/actions/vstudio/vc2010/test_header.lua +++ b/tests/actions/vstudio/vc2010/test_header.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2011-2012 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_vc2010_header") - local vc2010 = premake.vstudio.vc2010 + local vc2010 = p.vstudio.vc2010 -- @@ -14,7 +15,7 @@ -- function suite.project_on2010() - premake.action.set("vs2010") + p.action.set("vs2010") vc2010.project() test.capture [[ @@ -22,7 +23,7 @@ end function suite.project_on2011() - premake.action.set("vs2012") + p.action.set("vs2012") vc2010.project() test.capture [[ @@ -30,7 +31,7 @@ end function suite.project_on2013() - premake.action.set("vs2013") + p.action.set("vs2013") vc2010.project() test.capture [[ diff --git a/tests/actions/vstudio/vc2010/test_imagexex_settings.lua b/tests/actions/vstudio/vc2010/test_imagexex_settings.lua index 573d2ed9..a2303939 100644 --- a/tests/actions/vstudio/vc2010/test_imagexex_settings.lua +++ b/tests/actions/vstudio/vc2010/test_imagexex_settings.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2011-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_vs2010_imagexex_settings") - local vc2010 = premake.vstudio.vc2010 - local project = premake.project + local vc2010 = p.vstudio.vc2010 + local project = p.project -- diff --git a/tests/actions/vstudio/vc2010/test_item_def_group.lua b/tests/actions/vstudio/vc2010/test_item_def_group.lua index 76d00b58..1c92f2e2 100644 --- a/tests/actions/vstudio/vc2010/test_item_def_group.lua +++ b/tests/actions/vstudio/vc2010/test_item_def_group.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs2010_item_def_group") - local vc2010 = premake.vstudio.vc2010 - local project = premake.project + local vc2010 = p.vstudio.vc2010 + local project = p.project -- diff --git a/tests/actions/vstudio/vc2010/test_language_settings.lua b/tests/actions/vstudio/vc2010/test_language_settings.lua index 188c35cc..58cf6996 100644 --- a/tests/actions/vstudio/vc2010/test_language_settings.lua +++ b/tests/actions/vstudio/vc2010/test_language_settings.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs2010_language_settings") - local vc2010 = premake.vstudio.vc2010 - local project = premake.project + local vc2010 = p.vstudio.vc2010 + local project = p.project -- @@ -16,7 +17,7 @@ local wks function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") rule "MyRules" rule "MyOtherRules" wks = test.createWorkspace() diff --git a/tests/actions/vstudio/vc2010/test_language_targets.lua b/tests/actions/vstudio/vc2010/test_language_targets.lua index 1054b634..1065f24d 100644 --- a/tests/actions/vstudio/vc2010/test_language_targets.lua +++ b/tests/actions/vstudio/vc2010/test_language_targets.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs2010_language_targets") - local vc2010 = premake.vstudio.vc2010 - local project = premake.project + local vc2010 = p.vstudio.vc2010 + local project = p.project -- @@ -16,7 +17,7 @@ local wks function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") rule "MyRules" rule "MyOtherRules" wks = test.createWorkspace() diff --git a/tests/actions/vstudio/vc2010/test_link.lua b/tests/actions/vstudio/vc2010/test_link.lua index 56a74cf8..4455d935 100644 --- a/tests/actions/vstudio/vc2010/test_link.lua +++ b/tests/actions/vstudio/vc2010/test_link.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2011-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs2010_link") - local vc2010 = premake.vstudio.vc2010 - local project = premake.project + local vc2010 = p.vstudio.vc2010 + local project = p.project -- @@ -16,7 +17,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks, prj = test.createWorkspace() kind "SharedLib" end @@ -130,7 +131,7 @@ -- function suite.generateDebugInfo_onSymbolsOn_on2010() - premake.action.set("vs2010") + p.action.set("vs2010") symbols "On" prepare() test.capture [[ @@ -141,7 +142,7 @@ end function suite.generateDebugInfo_onSymbolsFastLink_on2010() - premake.action.set("vs2010") + p.action.set("vs2010") symbols "FastLink" prepare() test.capture [[ @@ -152,7 +153,7 @@ end function suite.generateDebugInfo_onSymbolsFull_on2010() - premake.action.set("vs2010") + p.action.set("vs2010") symbols "Full" prepare() test.capture [[ @@ -163,7 +164,7 @@ end function suite.generateDebugInfo_onSymbolsOn_on2015() - premake.action.set("vs2015") + p.action.set("vs2015") symbols "On" prepare() test.capture [[ @@ -174,7 +175,7 @@ end function suite.generateDebugInfo_onSymbolsFastLink_on2015() - premake.action.set("vs2015") + p.action.set("vs2015") symbols "FastLink" prepare() test.capture [[ @@ -186,7 +187,7 @@ end function suite.generateDebugInfo_onSymbolsFull_on2015() - premake.action.set("vs2015") + p.action.set("vs2015") symbols "Full" prepare() test.capture [[ @@ -197,7 +198,7 @@ end function suite.generateDebugInfo_onSymbolsFull_on2017() - premake.action.set("vs2017") + p.action.set("vs2017") symbols "Full" prepare() test.capture [[ diff --git a/tests/actions/vstudio/vc2010/test_manifest.lua b/tests/actions/vstudio/vc2010/test_manifest.lua index 456c8153..1cb1907f 100644 --- a/tests/actions/vstudio/vc2010/test_manifest.lua +++ b/tests/actions/vstudio/vc2010/test_manifest.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2009-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs2010_manifest") - local vc2010 = premake.vstudio.vc2010 - local project = premake.project + local vc2010 = p.vstudio.vc2010 + local project = p.project -- @@ -16,7 +17,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks, prj = test.createWorkspace() kind "ConsoleApp" end diff --git a/tests/actions/vstudio/vc2010/test_nmake_props.lua b/tests/actions/vstudio/vc2010/test_nmake_props.lua index a34a0644..ab93f516 100644 --- a/tests/actions/vstudio/vc2010/test_nmake_props.lua +++ b/tests/actions/vstudio/vc2010/test_nmake_props.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs2010_nmake_props") - local vc2010 = premake.vstudio.vc2010 + local vc2010 = p.vstudio.vc2010 -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks, prj = test.createWorkspace() kind "Makefile" end @@ -127,7 +128,7 @@ command 2 end function suite.onEscapedDefines() - premake.escaper(premake.vstudio.vs2010.esc) + p.escaper(p.vstudio.vs2010.esc) defines { "&", "<", ">" } prepare() test.capture [[ @@ -136,7 +137,7 @@ command 2 &;<;>;$(NMakePreprocessorDefinitions) ]] - premake.escaper(nil) + p.escaper(nil) end function suite.onIncludeDirs() diff --git a/tests/actions/vstudio/vc2010/test_nuget_packages_config.lua b/tests/actions/vstudio/vc2010/test_nuget_packages_config.lua index 44c4b89c..45e41523 100644 --- a/tests/actions/vstudio/vc2010/test_nuget_packages_config.lua +++ b/tests/actions/vstudio/vc2010/test_nuget_packages_config.lua @@ -4,10 +4,11 @@ -- Copyright (c) 2017 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs2010_nuget_packages_config") - local vc2010 = premake.vstudio.vc2010 - local nuget2010 = premake.vstudio.nuget2010 - local project = premake.project + local vc2010 = p.vstudio.vc2010 + local nuget2010 = p.vstudio.nuget2010 + local project = p.project -- @@ -17,12 +18,12 @@ local wks function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks = test.createWorkspace() end local function prepare() - local prj = premake.solution.getproject(wks, 1) + local prj = p.solution.getproject(wks, 1) nuget2010.generatePackagesConfig(prj) end diff --git a/tests/actions/vstudio/vc2010/test_output_props.lua b/tests/actions/vstudio/vc2010/test_output_props.lua index 93f4357e..1b2edf6f 100755 --- a/tests/actions/vstudio/vc2010/test_output_props.lua +++ b/tests/actions/vstudio/vc2010/test_output_props.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2011-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_vs2010_output_props") - local vc2010 = premake.vstudio.vc2010 + local vc2010 = p.vstudio.vc2010 -- @@ -15,7 +16,7 @@ local wks function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks, prj = test.createWorkspace() end diff --git a/tests/actions/vstudio/vc2010/test_platform_toolset.lua b/tests/actions/vstudio/vc2010/test_platform_toolset.lua index 464131d4..44748ff7 100644 --- a/tests/actions/vstudio/vc2010/test_platform_toolset.lua +++ b/tests/actions/vstudio/vc2010/test_platform_toolset.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2013-2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_vs2010_platform_toolset") - local vc2010 = premake.vstudio.vc2010 + local vc2010 = p.vstudio.vc2010 -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2012") + p.action.set("vs2012") wks, prj = test.createWorkspace() files "hello.cpp" end @@ -32,14 +33,14 @@ -- function suite.correctDefault_onVS2010() - premake.action.set("vs2010") + p.action.set("vs2010") prepare() test.isemptycapture() end function suite.correctDefault_onVS2012() - premake.action.set("vs2012") + p.action.set("vs2012") prepare() test.capture [[ v110 @@ -48,7 +49,7 @@ function suite.correctDefault_onVS2013() - premake.action.set("vs2013") + p.action.set("vs2013") prepare() test.capture [[ v120 diff --git a/tests/actions/vstudio/vc2010/test_project_configs.lua b/tests/actions/vstudio/vc2010/test_project_configs.lua index 6fdd11db..989b9e04 100755 --- a/tests/actions/vstudio/vc2010/test_project_configs.lua +++ b/tests/actions/vstudio/vc2010/test_project_configs.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2009-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_vc2010_project_configs") - local vc2010 = premake.vstudio.vc2010 + local vc2010 = p.vstudio.vc2010 -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks = test.createWorkspace() end diff --git a/tests/actions/vstudio/vc2010/test_project_refs.lua b/tests/actions/vstudio/vc2010/test_project_refs.lua index 58fcfa31..d4b66332 100644 --- a/tests/actions/vstudio/vc2010/test_project_refs.lua +++ b/tests/actions/vstudio/vc2010/test_project_refs.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2011-2012 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_vs2010_project_refs") - local vc2010 = premake.vstudio.vc2010 + local vc2010 = p.vstudio.vc2010 -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks = test.createWorkspace() uuid "00112233-4455-6677-8888-99AABBCCDDEE" test.createproject(wks) diff --git a/tests/actions/vstudio/vc2010/test_prop_sheet.lua b/tests/actions/vstudio/vc2010/test_prop_sheet.lua index 175f6f00..a3437834 100755 --- a/tests/actions/vstudio/vc2010/test_prop_sheet.lua +++ b/tests/actions/vstudio/vc2010/test_prop_sheet.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2011-2012 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_vs2010_prop_sheet") - local vc2010 = premake.vstudio.vc2010 - local project = premake.project + local vc2010 = p.vstudio.vc2010 + local project = p.project -- @@ -16,7 +17,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks, prj = test.createWorkspace() end diff --git a/tests/actions/vstudio/vc2010/test_resource_compile.lua b/tests/actions/vstudio/vc2010/test_resource_compile.lua index e7423dd0..8135d557 100755 --- a/tests/actions/vstudio/vc2010/test_resource_compile.lua +++ b/tests/actions/vstudio/vc2010/test_resource_compile.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2011-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vs2010_resource_compiler") - local vc2010 = premake.vstudio.vc2010 - local project = premake.project + local vc2010 = p.vstudio.vc2010 + local project = p.project -- @@ -16,8 +17,8 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") - premake.escaper(premake.vstudio.vs2010.esc) + p.action.set("vs2010") + p.escaper(p.vstudio.vs2010.esc) wks, prj = test.createWorkspace() end diff --git a/tests/actions/vstudio/vc2010/test_rule_props.lua b/tests/actions/vstudio/vc2010/test_rule_props.lua index 767f4102..b5f34ea7 100644 --- a/tests/actions/vstudio/vc2010/test_rule_props.lua +++ b/tests/actions/vstudio/vc2010/test_rule_props.lua @@ -5,10 +5,10 @@ -- Copyright (c) 2016 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_vs2010_rule_props") - - local vc2010 = premake.vstudio.vc2010 - local m = premake.vstudio.vs2010.rules.props + local vc2010 = p.vstudio.vc2010 + local m = p.vstudio.vs2010.rules.props -- @@ -18,7 +18,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") rule 'example' display 'Example compiler' fileExtension '.example' diff --git a/tests/actions/vstudio/vc2010/test_rule_targets.lua b/tests/actions/vstudio/vc2010/test_rule_targets.lua index f17a3745..21bda828 100644 --- a/tests/actions/vstudio/vc2010/test_rule_targets.lua +++ b/tests/actions/vstudio/vc2010/test_rule_targets.lua @@ -5,10 +5,10 @@ -- Copyright (c) 2016 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_vs2010_rule_targets") - - local vc2010 = premake.vstudio.vc2010 - local m = premake.vstudio.vs2010.rules.targets + local vc2010 = p.vstudio.vc2010 + local m = p.vstudio.vs2010.rules.targets @@ -19,7 +19,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") rule 'example' display 'Example compiler' fileExtension '.example' diff --git a/tests/actions/vstudio/vc2010/test_rule_vars.lua b/tests/actions/vstudio/vc2010/test_rule_vars.lua index 6314a75c..50872e74 100644 --- a/tests/actions/vstudio/vc2010/test_rule_vars.lua +++ b/tests/actions/vstudio/vc2010/test_rule_vars.lua @@ -5,9 +5,9 @@ -- Copyright (c) 2014-2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_vs2010_rule_vars") - - local vc2010 = premake.vstudio.vc2010 + local vc2010 = p.vstudio.vc2010 @@ -18,7 +18,7 @@ local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") rule "MyRule" wks, prj = test.createWorkspace() rules { "MyRule" } diff --git a/tests/actions/vstudio/vc2010/test_rule_xml.lua b/tests/actions/vstudio/vc2010/test_rule_xml.lua index 015434b8..a47bb77f 100644 --- a/tests/actions/vstudio/vc2010/test_rule_xml.lua +++ b/tests/actions/vstudio/vc2010/test_rule_xml.lua @@ -5,10 +5,10 @@ -- Copyright (c) 2016 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_vs2010_rule_xml") - - local vc2010 = premake.vstudio.vc2010 - local m = premake.vstudio.vs2010.rules.xml + local vc2010 = p.vstudio.vc2010 + local m = p.vstudio.vs2010.rules.xml -- @@ -16,7 +16,7 @@ -- function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") rule "MyRule" wks, prj = test.createWorkspace() rules { "MyRule" } diff --git a/tests/actions/vstudio/vc2010/test_target_machine.lua b/tests/actions/vstudio/vc2010/test_target_machine.lua index 8402772b..73968bc3 100644 --- a/tests/actions/vstudio/vc2010/test_target_machine.lua +++ b/tests/actions/vstudio/vc2010/test_target_machine.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2015 Jason Perkins and the Premake project --- + local p = premake local suite = test.declare("vstudio_vs2010_target_machine") - local vc2010 = premake.vstudio.vc2010 + local vc2010 = p.vstudio.vc2010 -- diff --git a/tests/actions/vstudio/vc2010/test_user_file.lua b/tests/actions/vstudio/vc2010/test_user_file.lua index 1a995655..d34b9c44 100644 --- a/tests/actions/vstudio/vc2010/test_user_file.lua +++ b/tests/actions/vstudio/vc2010/test_user_file.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("vstudio_vs2010_user_file") - local vc2010 = premake.vstudio.vc2010 + local vc2010 = p.vstudio.vc2010 -- @@ -15,7 +16,7 @@ local wks function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks = test.createWorkspace() end diff --git a/tests/actions/vstudio/vc2010/test_vectorextensions.lua b/tests/actions/vstudio/vc2010/test_vectorextensions.lua index 7c50df72..313248dc 100644 --- a/tests/actions/vstudio/vc2010/test_vectorextensions.lua +++ b/tests/actions/vstudio/vc2010/test_vectorextensions.lua @@ -6,14 +6,15 @@ -- Copyright (c) 2015 Jason Perkins and the Premake project --- + local p = premake local suite = test.declare("vs2010_vc_vectorextensions") - local m = premake.vstudio.vc2010 + local m = p.vstudio.vc2010 local wks, prj function suite.setup() - premake.action.set("vs2010") + p.action.set("vs2010") wks, prj = test.createWorkspace() end @@ -36,7 +37,7 @@ end function suite.instructionSet_onIA32() - premake.action.set("vs2012") + p.action.set("vs2012") vectorextensions "IA32" prepare() test.capture [[ @@ -61,7 +62,7 @@ end function suite.instructionSet_onAVX() - premake.action.set("vs2013") + p.action.set("vs2013") vectorextensions "AVX" prepare() test.capture [[ @@ -76,7 +77,7 @@ end function suite.instructionSet_onAVX2() - premake.action.set("vs2013") + p.action.set("vs2013") vectorextensions "AVX2" prepare() test.capture [[ @@ -85,7 +86,7 @@ end function suite.instructionSet_onAVX2_onVS2012() - premake.action.set("vs2012") + p.action.set("vs2012") vectorextensions "AVX2" prepare() test.isemptycapture() diff --git a/tests/api/test_boolean_kind.lua b/tests/api/test_boolean_kind.lua index 77ab4bdf..78178764 100644 --- a/tests/api/test_boolean_kind.lua +++ b/tests/api/test_boolean_kind.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("api_boolean_kind") - local api = premake.api + local api = p.api -- diff --git a/tests/api/test_containers.lua b/tests/api/test_containers.lua index 5406dc63..eb500040 100644 --- a/tests/api/test_containers.lua +++ b/tests/api/test_containers.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2013-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("api_containers") - local api = premake.api + local api = p.api -- @@ -24,7 +25,7 @@ -- function suite.workspace_createsOnFirstUse() - test.isnotnil(premake.global.getWorkspace("MyWorkspace")) + test.isnotnil(p.global.getWorkspace("MyWorkspace")) end function suite.project_createsOnFirstUse() diff --git a/tests/api/test_deprecations.lua b/tests/api/test_deprecations.lua index 13323e51..4a129e48 100644 --- a/tests/api/test_deprecations.lua +++ b/tests/api/test_deprecations.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2012-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("api_deprecations") - local api = premake.api + local api = p.api function suite.setup() diff --git a/tests/api/test_directory_kind.lua b/tests/api/test_directory_kind.lua index a7a5cfcc..383ad0a1 100644 --- a/tests/api/test_directory_kind.lua +++ b/tests/api/test_directory_kind.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("api_directory_kind") - local api = premake.api + local api = p.api -- diff --git a/tests/api/test_list_kind.lua b/tests/api/test_list_kind.lua index 31682c07..e60218cb 100644 --- a/tests/api/test_list_kind.lua +++ b/tests/api/test_list_kind.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2012 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("api_list_kind") - local api = premake.api + local api = p.api -- diff --git a/tests/api/test_path_kind.lua b/tests/api/test_path_kind.lua index 8bb87c16..9d99c5cd 100644 --- a/tests/api/test_path_kind.lua +++ b/tests/api/test_path_kind.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2012 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("api_path_kind") - local api = premake.api + local api = p.api -- diff --git a/tests/api/test_register.lua b/tests/api/test_register.lua index 2fead38b..28ac9c4c 100644 --- a/tests/api/test_register.lua +++ b/tests/api/test_register.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2012 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("api_register") - local api = premake.api + local api = p.api -- @@ -23,7 +24,7 @@ -- function suite.registerFunctionExists() - test.isequal("function", type(premake.api.register)) + test.isequal("function", type(p.api.register)) end diff --git a/tests/api/test_string_kind.lua b/tests/api/test_string_kind.lua index 00e459d4..e6714fed 100644 --- a/tests/api/test_string_kind.lua +++ b/tests/api/test_string_kind.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2012 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("api_string_kind") - local api = premake.api + local api = p.api -- diff --git a/tests/api/test_table_kind.lua b/tests/api/test_table_kind.lua index 28f5d455..8a4b30aa 100644 --- a/tests/api/test_table_kind.lua +++ b/tests/api/test_table_kind.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2012-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("api_table_kind") - local api = premake.api + local api = p.api -- diff --git a/tests/base/test_configset.lua b/tests/base/test_configset.lua index c31c7240..e65737a7 100644 --- a/tests/base/test_configset.lua +++ b/tests/base/test_configset.lua @@ -4,10 +4,10 @@ -- Copyright (c) 2012-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("configset") - - local configset = premake.configset - local field = premake.field + local configset = p.configset + local field = p.field -- diff --git a/tests/base/test_context.lua b/tests/base/test_context.lua index eeee0e8b..f04ee7ba 100644 --- a/tests/base/test_context.lua +++ b/tests/base/test_context.lua @@ -4,11 +4,11 @@ -- Copyright (c) 2012-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("context") - - local context = premake.context - local configset = premake.configset - local field = premake.field + local context = p.context + local configset = p.configset + local field = p.field -- diff --git a/tests/base/test_criteria.lua b/tests/base/test_criteria.lua index 49bdebbf..78f29f31 100644 --- a/tests/base/test_criteria.lua +++ b/tests/base/test_criteria.lua @@ -4,9 +4,9 @@ -- Copyright (c) 2012-2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("criteria") - - local criteria = premake.criteria + local criteria = p.criteria -- @@ -315,13 +315,13 @@ -- function suite.passes_onAliasedValue() - premake.api.addAliases("system", { ["gnu-linux"] = "linux" }) + p.api.addAliases("system", { ["gnu-linux"] = "linux" }) crit = criteria.new { "system:gnu-linux" } test.istrue(criteria.matches(crit, { system="linux" })) end function suite.passes_onAliasedValue_withMixedCase() - premake.api.addAliases("system", { ["gnu-linux"] = "linux" }) + p.api.addAliases("system", { ["gnu-linux"] = "linux" }) crit = criteria.new { "System:GNU-Linux" } test.istrue(criteria.matches(crit, { system="linux" })) end diff --git a/tests/base/test_detoken.lua b/tests/base/test_detoken.lua index c4d1d16c..51524180 100644 --- a/tests/base/test_detoken.lua +++ b/tests/base/test_detoken.lua @@ -4,9 +4,9 @@ -- Copyright (c) 2011-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("detoken") - - local detoken = premake.detoken + local detoken = p.detoken -- @@ -17,7 +17,7 @@ local environ = {} function suite.setup() - action = premake.action.get("test") + action = p.action.get("test") end function suite.teardown() diff --git a/tests/base/test_include.lua b/tests/base/test_include.lua index 9c7aa1cb..42b1ce6d 100644 --- a/tests/base/test_include.lua +++ b/tests/base/test_include.lua @@ -5,6 +5,7 @@ -- + local p = premake local suite = test.declare("include") @@ -24,43 +25,43 @@ function suite.include_findsPremakeFile_onFolderNameOnly() include (_TESTS_DIR .. "/folder") - test.isequal("ok", premake.captured()) + test.isequal("ok", p.captured()) end function suite.include_onExactFilename() include (_TESTS_DIR .. "/folder/premake5.lua") - test.isequal("ok", premake.captured()) + test.isequal("ok", p.captured()) end function suite.include_runsOnlyOnce_onMultipleIncludes() include (_TESTS_DIR .. "/folder/premake5.lua") include (_TESTS_DIR .. "/folder/premake5.lua") - test.isequal("ok", premake.captured()) + test.isequal("ok", p.captured()) end function suite.include_runsOnlyOnce_onMultipleIncludesWithDifferentPaths() include (_TESTS_DIR .. "/folder/premake5.lua") include (_TESTS_DIR .. "/../tests/folder/premake5.lua") - test.isequal("ok", premake.captured()) + test.isequal("ok", p.captured()) end function suite.includeexternal_runs() includeexternal (_TESTS_DIR .. "/folder/premake5.lua") - test.isequal("ok", premake.captured()) + test.isequal("ok", p.captured()) end function suite.includeexternal_runsAfterInclude() include (_TESTS_DIR .. "/folder/premake5.lua") includeexternal (_TESTS_DIR .. "/folder/premake5.lua") - test.isequal("okok", premake.captured()) + test.isequal("okok", p.captured()) end function suite.includeexternal_runsTwiceAfterInclude() include (_TESTS_DIR .. "/folder/premake5.lua") includeexternal (_TESTS_DIR .. "/folder/premake5.lua") includeexternal (_TESTS_DIR .. "/folder/premake5.lua") - test.isequal("okokok", premake.captured()) + test.isequal("okokok", p.captured()) end diff --git a/tests/base/test_module_loader.lua b/tests/base/test_module_loader.lua index 3f747ff5..78eebf9e 100644 --- a/tests/base/test_module_loader.lua +++ b/tests/base/test_module_loader.lua @@ -4,6 +4,7 @@ -- Copyright (c) 2012-2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("module_loader") -- @@ -14,7 +15,7 @@ function suite.setup() table.insert(package.loaders, function (name) - premake.out(name) + p.out(name) return loadstring("") end) loaderIndex = #package.loaders diff --git a/tests/base/test_option.lua b/tests/base/test_option.lua index 6489b4b0..c3181839 100644 --- a/tests/base/test_option.lua +++ b/tests/base/test_option.lua @@ -4,6 +4,7 @@ -- Copyright (c) 2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("base_option") @@ -40,5 +41,5 @@ description = "Testing", } - test.isnotnil(premake.option.get("testopt2")) + test.isnotnil(p.option.get("testopt2")) end diff --git a/tests/base/test_override.lua b/tests/base/test_override.lua index dabdc891..284af330 100644 --- a/tests/base/test_override.lua +++ b/tests/base/test_override.lua @@ -5,6 +5,7 @@ -- + local p = premake local suite = test.declare("base_override") @@ -26,7 +27,7 @@ -- function suite.canOverride() - premake.override(X, "testfunc", function() + p.override(X, "testfunc", function() return "canOverride" end) test.isequal("canOverride", X.testfunc()) @@ -38,7 +39,7 @@ -- function suite.canCallOriginal() - premake.override(X, "testfunc", function(base) + p.override(X, "testfunc", function(base) return "canOverride > " .. base() end) test.isequal("canOverride > testfunc", X.testfunc()) @@ -50,7 +51,7 @@ -- function suite.canPassThroughArguments() - premake.override(X, "testfunc", function(base, value) + p.override(X, "testfunc", function(base, value) return value .. " > " .. base() end) test.isequal("testval > testfunc", X.testfunc("testval")) @@ -62,11 +63,11 @@ -- function suite.canOverrideMultipleTimes() - premake.override(X, "testfunc", function(base, value) + p.override(X, "testfunc", function(base, value) return string.format("[%s > %s]", value, base("base1")) end) - premake.override(X, "testfunc", function(base, value) + p.override(X, "testfunc", function(base, value) return string.format("{%s > %s}", value, base("base2")) end) diff --git a/tests/base/test_tree.lua b/tests/base/test_tree.lua index eafa7501..7591ef43 100644 --- a/tests/base/test_tree.lua +++ b/tests/base/test_tree.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2009-2012 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("base_tree") - local tree = premake.tree + local tree = p.tree -- diff --git a/tests/config/test_linkinfo.lua b/tests/config/test_linkinfo.lua index 4bcdaa37..1365c377 100755 --- a/tests/config/test_linkinfo.lua +++ b/tests/config/test_linkinfo.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2012-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("config_linkinfo") - local config = premake.config + local config = p.config -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("test") + p.action.set("test") wks, prj = test.createWorkspace() kind "StaticLib" system "Windows" diff --git a/tests/config/test_links.lua b/tests/config/test_links.lua index 67f68a33..3acad79e 100755 --- a/tests/config/test_links.lua +++ b/tests/config/test_links.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2012-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("config_links") - local config = premake.config + local config = p.config -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("test") + p.action.set("test") _TARGET_OS = "windows" wks, prj = test.createWorkspace() end diff --git a/tests/config/test_targetinfo.lua b/tests/config/test_targetinfo.lua index bad4b393..12252a4c 100755 --- a/tests/config/test_targetinfo.lua +++ b/tests/config/test_targetinfo.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2011-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("config_targetinfo") - local config = premake.config + local config = p.config -- @@ -15,7 +16,7 @@ local wks, prj function suite.setup() - premake.action.set("test") + p.action.set("test") wks, prj = test.createWorkspace() system "macosx" end diff --git a/tests/oven/test_filtering.lua b/tests/oven/test_filtering.lua index f556bd7b..a9906a5b 100644 --- a/tests/oven/test_filtering.lua +++ b/tests/oven/test_filtering.lua @@ -4,6 +4,7 @@ -- Copyright (c) 2011-2014 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("oven_filtering") @@ -29,7 +30,7 @@ -- function suite.onAction() - premake.action.set("vs2012") + p.action.set("vs2012") filter { "action:vs2012" } defines { "USE_VS2012" } prepare() @@ -37,7 +38,7 @@ end function suite.onActionMismatch() - premake.action.set("vs2010") + p.action.set("vs2010") filter { "action:vs2012" } defines { "USE_VS2012" } prepare() diff --git a/tests/oven/test_objdirs.lua b/tests/oven/test_objdirs.lua index 0fad6620..ecb5019c 100644 --- a/tests/oven/test_objdirs.lua +++ b/tests/oven/test_objdirs.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2014-2015 Jason Perkins and the Premake project --- + local p = premake local suite = test.declare("oven_objdirs") - local oven = premake.oven + local oven = p.oven --- -- Setup diff --git a/tests/project/test_eachconfig.lua b/tests/project/test_eachconfig.lua index 7ef4d903..08bb354b 100755 --- a/tests/project/test_eachconfig.lua +++ b/tests/project/test_eachconfig.lua @@ -4,6 +4,7 @@ -- Copyright (c) 2011-2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("project_eachconfig") @@ -23,7 +24,7 @@ configurations ( buildcfgs ) end prj = test.getproject(wks, 1) - for cfg in premake.project.eachconfig(prj) do + for cfg in p.project.eachconfig(prj) do _p(2,'%s:%s', cfg.buildcfg or "", cfg.platform or "") end end diff --git a/tests/project/test_sources.lua b/tests/project/test_sources.lua index c5d52c93..84f5ee57 100644 --- a/tests/project/test_sources.lua +++ b/tests/project/test_sources.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2011-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("project_sources") - local project = premake.project + local project = p.project -- @@ -25,7 +26,7 @@ os.chdir(cwd) -- Create a token to be used in search paths - premake.api.register { name = "mytoken", kind = "string", scope = "config" } + p.api.register { name = "mytoken", kind = "string", scope = "config" } mytoken "test" end diff --git a/tests/project/test_vpaths.lua b/tests/project/test_vpaths.lua index 84850b49..63a58d8d 100644 --- a/tests/project/test_vpaths.lua +++ b/tests/project/test_vpaths.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2011-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("project_vpaths") - local project = premake.project + local project = p.project -- diff --git a/tests/tools/test_dotnet.lua b/tests/tools/test_dotnet.lua index cd86946b..8ed7c8a7 100644 --- a/tests/tools/test_dotnet.lua +++ b/tests/tools/test_dotnet.lua @@ -4,8 +4,9 @@ -- Copyright (c) 2012-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("tools_dotnet") - local dotnet = premake.tools.dotnet + local dotnet = p.tools.dotnet -- diff --git a/tests/tools/test_gcc.lua b/tests/tools/test_gcc.lua index 7aa35e42..06f6d812 100644 --- a/tests/tools/test_gcc.lua +++ b/tests/tools/test_gcc.lua @@ -4,10 +4,11 @@ -- Copyright (c) 2009-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("tools_gcc") - local gcc = premake.tools.gcc - local project = premake.project + local gcc = p.tools.gcc + local project = p.project -- diff --git a/tests/tools/test_msc.lua b/tests/tools/test_msc.lua index 78456367..efc8cc8c 100644 --- a/tests/tools/test_msc.lua +++ b/tests/tools/test_msc.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2012-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("tools_msc") - local msc = premake.tools.msc + local msc = p.tools.msc -- diff --git a/tests/tools/test_snc.lua b/tests/tools/test_snc.lua index 2acba0f8..fefc6e8f 100644 --- a/tests/tools/test_snc.lua +++ b/tests/tools/test_snc.lua @@ -4,9 +4,10 @@ -- Copyright (c) 2012-2013 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("tools_snc") - local snc = premake.tools.snc + local snc = p.tools.snc -- diff --git a/tests/workspace/test_objdirs.lua b/tests/workspace/test_objdirs.lua index c2590e8f..ad74c9f7 100644 --- a/tests/workspace/test_objdirs.lua +++ b/tests/workspace/test_objdirs.lua @@ -4,6 +4,7 @@ -- Copyright (c) 2012-2015 Jason Perkins and the Premake project -- + local p = premake local suite = test.declare("workspace_objdir") @@ -14,7 +15,7 @@ local wks function suite.setup() - premake.action.set("test") + p.action.set("test") wks = workspace("MyWorkspace") system "macosx" end @@ -23,7 +24,7 @@ local platforms = wks.platforms or {} local prj = project("MyProject") local cfg = test.getconfig(prj, "Debug", platforms[1]) - return premake.project.getrelative(cfg.project, cfg.objdir) + return p.project.getrelative(cfg.project, cfg.objdir) end From b251234b27c945e407adbd964e52c6c77d7e1419 Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Wed, 26 Apr 2017 03:15:33 +1000 Subject: [PATCH 48/59] Cleaned up inconsistencies in whitespace --- modules/codelite/_preload.lua | 2 +- modules/d/actions/gmake.lua | 4 +- modules/d/tools/dmd.lua | 2 +- modules/d/tools/gdc.lua | 2 +- modules/d/tools/ldc.lua | 2 +- modules/raw/_preload.lua | 14 +-- modules/raw/raw_action.lua | 108 +++++++++--------- modules/xcode/xcode_common.lua | 4 +- modules/xcode/xcode_project.lua | 88 +++++++------- src/_premake_init.lua | 2 +- src/actions/make/make_csharp.lua | 6 +- src/base/api.lua | 12 +- src/base/config.lua | 2 +- src/base/path.lua | 2 +- src/base/project.lua | 6 +- src/host/os_islink.c | 8 +- src/host/os_stat.c | 2 +- src/host/premake.c | 12 +- src/tools/dotnet.lua | 2 +- src/tools/gcc.lua | 2 +- tests/actions/make/cpp/test_clang.lua | 2 +- tests/actions/make/cpp/test_file_rules.lua | 4 +- tests/actions/make/cpp/test_make_linking.lua | 40 +++---- tests/actions/make/cpp/test_objects.lua | 8 +- tests/actions/make/cpp/test_target_rules.lua | 4 +- tests/actions/make/cpp/test_tools.lua | 2 +- tests/actions/make/cpp/test_wiidev.lua | 2 +- tests/actions/make/cs/test_embed_files.lua | 12 +- tests/actions/make/cs/test_flags.lua | 12 +- tests/actions/make/cs/test_links.lua | 58 +++++----- tests/actions/make/cs/test_sources.lua | 12 +- .../actions/vstudio/vc2010/test_build_log.lua | 2 +- tests/base/test_configset.lua | 6 +- tests/base/test_path.lua | 16 +-- tests/oven/test_filtering.lua | 2 +- tests/project/test_vpaths.lua | 10 +- 36 files changed, 237 insertions(+), 237 deletions(-) diff --git a/modules/codelite/_preload.lua b/modules/codelite/_preload.lua index be544968..e62002c2 100644 --- a/modules/codelite/_preload.lua +++ b/modules/codelite/_preload.lua @@ -23,7 +23,7 @@ valid_kinds = { "ConsoleApp", "WindowedApp", "Makefile", "SharedLib", "StaticLib", "Utility" }, valid_tools = { - cc = { "gcc", "clang", "msc" } + cc = { "gcc", "clang", "msc" } }, supports_language = function(lang) return p.languages.isc(lang) or diff --git a/modules/d/actions/gmake.lua b/modules/d/actions/gmake.lua index 6aa148e7..020ba547 100644 --- a/modules/d/actions/gmake.lua +++ b/modules/d/actions/gmake.lua @@ -159,8 +159,8 @@ _p('\t@echo $(notdir $<)') _p('\t$(SILENT) $(DC) $(ALL_DFLAGS) $(OUTPUTFLAG) -c $<') else - oldfn(prj, node) - end + oldfn(prj, node) + end end) diff --git a/modules/d/tools/dmd.lua b/modules/d/tools/dmd.lua index 59161946..a4c8a6f2 100644 --- a/modules/d/tools/dmd.lua +++ b/modules/d/tools/dmd.lua @@ -9,7 +9,7 @@ local p = premake local project = p.project local config = p.config - local d = p.modules.d + local d = p.modules.d -- -- Set default tools diff --git a/modules/d/tools/gdc.lua b/modules/d/tools/gdc.lua index 21dc08c3..64bcfe41 100644 --- a/modules/d/tools/gdc.lua +++ b/modules/d/tools/gdc.lua @@ -10,7 +10,7 @@ local gdc = p.tools.gdc local project = p.project local config = p.config - local d = p.modules.d + local d = p.modules.d -- -- Set default tools diff --git a/modules/d/tools/ldc.lua b/modules/d/tools/ldc.lua index 4d461885..95261a40 100644 --- a/modules/d/tools/ldc.lua +++ b/modules/d/tools/ldc.lua @@ -10,7 +10,7 @@ local ldc = p.tools.ldc local project = p.project local config = p.config - local d = p.modules.d + local d = p.modules.d -- diff --git a/modules/raw/_preload.lua b/modules/raw/_preload.lua index 3c056a2e..d133500e 100644 --- a/modules/raw/_preload.lua +++ b/modules/raw/_preload.lua @@ -1,14 +1,14 @@ newaction { - trigger = "raw", - shortname = "Raw output", - description = "Generate raw representation of Premake structures", + trigger = "raw", + shortname = "Raw output", + description = "Generate raw representation of Premake structures", - onsolution = function(sln) - require('raw') + onsolution = function(sln) + require('raw') - premake.generate(sln, ".raw", premake.raw.solution) - end, + premake.generate(sln, ".raw", premake.raw.solution) + end, } return function(cfg) diff --git a/modules/raw/raw_action.lua b/modules/raw/raw_action.lua index f2539105..211249cf 100644 --- a/modules/raw/raw_action.lua +++ b/modules/raw/raw_action.lua @@ -4,73 +4,73 @@ local raw = p.raw local gvisited = { } function raw.solution(sln) - if not gvisited[sln.global] then - gvisited[sln.global] = true - raw.printTable({ global = sln.global }) - end + if not gvisited[sln.global] then + gvisited[sln.global] = true + raw.printTable({ global = sln.global }) + end end function raw.printTable(t, i) - i = i or 0 - placement = raw._createPlacement(t) - raw._printTableRecursive(t, i, placement) + i = i or 0 + placement = raw._createPlacement(t) + raw._printTableRecursive(t, i, placement) end function raw._printTableRecursive(t, i, placement) - elements = { } - for k, v in pairs(t) do - table.insert(elements, { key = k, value = v }) - end + elements = { } + for k, v in pairs(t) do + table.insert(elements, { key = k, value = v }) + end - table.sort(elements, function(a, b) - local n1 = type(a.key) == "number" - local n2 = type(b.key) == "number" - if n1 ~= n2 then - return n1 - end + table.sort(elements, function(a, b) + local n1 = type(a.key) == "number" + local n2 = type(b.key) == "number" + if n1 ~= n2 then + return n1 + end - local k1 = n1 and a.key or raw._encode(a.key) - local k2 = n2 and b.key or raw._encode(b.key) - return k1 < k2 - end) + local k1 = n1 and a.key or raw._encode(a.key) + local k2 = n2 and b.key or raw._encode(b.key) + return k1 < k2 + end) - for _, elem in ipairs(elements) do - p = placement[elem.value] - if p and elem.key == p.key and t == p.parent then - _p(i, "%s", raw._encode(elem.key) .. ': ' .. raw._encode(elem.value) .. ' {') - raw._printTableRecursive(elem.value, i + 1, placement) - _p(i, '} # ' .. raw._encode(elem.key)) - else - _p(i, "%s", raw._encode(elem.key) .. ': ' .. raw._encode(elem.value)) - end - end + for _, elem in ipairs(elements) do + p = placement[elem.value] + if p and elem.key == p.key and t == p.parent then + _p(i, "%s", raw._encode(elem.key) .. ': ' .. raw._encode(elem.value) .. ' {') + raw._printTableRecursive(elem.value, i + 1, placement) + _p(i, '} # ' .. raw._encode(elem.key)) + else + _p(i, "%s", raw._encode(elem.key) .. ': ' .. raw._encode(elem.value)) + end + end end function raw._createPlacement(tbl) - placement = { } - placementList = { tbl } - while #placementList ~= 0 do - parentList = { } - for _, parent in ipairs(placementList) do - for k, v in pairs(parent) do - if type(v) == "table" and not placement[v] then - table.insert(parentList, v) - placement[v] = { - parent = parent, - key = k - } - end - end - end - placementList = parentList - end - return placement + placement = { } + placementList = { tbl } + while #placementList ~= 0 do + parentList = { } + for _, parent in ipairs(placementList) do + for k, v in pairs(parent) do + if type(v) == "table" and not placement[v] then + table.insert(parentList, v) + placement[v] = { + parent = parent, + key = k + } + end + end + end + placementList = parentList + end + return placement end function raw._encode(v) - if type(v) == "string" then - return '"' .. v .. '"' - else - return tostring(v) - end + if type(v) == "string" then + return '"' .. v .. '"' + else + return tostring(v) + end end diff --git a/modules/xcode/xcode_common.lua b/modules/xcode/xcode_common.lua index c15992ba..3670ebb6 100644 --- a/modules/xcode/xcode_common.lua +++ b/modules/xcode/xcode_common.lua @@ -7,9 +7,9 @@ local p = premake local xcode = p.modules.xcode local tree = p.tree - local workspace = p.workspace + local workspace = p.workspace local project = p.project - local config = p.config + local config = p.config local fileconfig = p.fileconfig diff --git a/modules/xcode/xcode_project.lua b/modules/xcode/xcode_project.lua index 8a968e46..819b7723 100644 --- a/modules/xcode/xcode_project.lua +++ b/modules/xcode/xcode_project.lua @@ -39,33 +39,33 @@ table.insert(tr.configs, cfg) end - -- convert localized resources from their filesystem layout (English.lproj/MainMenu.xib) + -- convert localized resources from their filesystem layout (English.lproj/MainMenu.xib) -- to Xcode's display layout (MainMenu.xib/English). - tree.traverse(tr, { - onbranch = function(node) - if path.getextension(node.name) == ".lproj" then - local lang = path.getbasename(node.name) -- "English", "French", etc. + tree.traverse(tr, { + onbranch = function(node) + if path.getextension(node.name) == ".lproj" then + local lang = path.getbasename(node.name) -- "English", "French", etc. - -- create a new language group for each file it contains - for _, filenode in ipairs(node.children) do - local grpnode = node.parent.children[filenode.name] - if not grpnode then - grpnode = tree.insert(node.parent, tree.new(filenode.name)) - grpnode.kind = "vgroup" - end + -- create a new language group for each file it contains + for _, filenode in ipairs(node.children) do + local grpnode = node.parent.children[filenode.name] + if not grpnode then + grpnode = tree.insert(node.parent, tree.new(filenode.name)) + grpnode.kind = "vgroup" + end - -- convert the file node to a language node and add to the group - filenode.name = path.getbasename(lang) - tree.insert(grpnode, filenode) - end + -- convert the file node to a language node and add to the group + filenode.name = path.getbasename(lang) + tree.insert(grpnode, filenode) + end -- remove this directory from the tree - tree.remove(node) - end - end - }) + tree.remove(node) + end + end + }) - -- the special folder "Frameworks" lists all linked frameworks + -- the special folder "Frameworks" lists all linked frameworks tr.frameworks = tree.new("Frameworks") for cfg in project.eachconfig(prj) do for _, link in ipairs(config.getlinks(cfg, "system", "fullpath")) do @@ -73,9 +73,9 @@ if xcode.isframework(name) and not tr.frameworks.children[name] then node = tree.insert(tr.frameworks, tree.new(name)) node.path = link - end - end - end + end + end + end -- only add it to the tree if there are frameworks to link if #tr.frameworks.children > 0 then @@ -84,7 +84,7 @@ -- the special folder "Products" holds the target produced by the project; this -- is populated below - tr.products = tree.insert(tr, tree.new("Products")) + tr.products = tree.insert(tr, tree.new("Products")) -- the special folder "Projects" lists sibling project dependencies tr.projects = tree.new("Projects") @@ -95,31 +95,31 @@ xcode.addDependency(prj, tr, dep, false) end - if #tr.projects.children > 0 then - tree.insert(tr, tr.projects) - end + if #tr.projects.children > 0 then + tree.insert(tr, tr.projects) + end - -- Final setup - tree.traverse(tr, { - onnode = function(node) - -- assign IDs to every node in the tree - node.id = xcode.newid(node.name, nil, node.path) + -- Final setup + tree.traverse(tr, { + onnode = function(node) + -- assign IDs to every node in the tree + node.id = xcode.newid(node.name, nil, node.path) - node.isResource = xcode.isItemResource(prj, node) + node.isResource = xcode.isItemResource(prj, node) - -- assign build IDs to buildable files + -- assign build IDs to buildable files if xcode.getbuildcategory(node) and not node.excludefrombuild then - node.buildid = xcode.newid(node.name, "build", node.path) - end + node.buildid = xcode.newid(node.name, "build", node.path) + end - -- remember key files that are needed elsewhere - if string.endswith(node.name, "Info.plist") then - tr.infoplist = node - end - end - }, true) + -- remember key files that are needed elsewhere + if string.endswith(node.name, "Info.plist") then + tr.infoplist = node + end + end + }, true) - -- Plug in the product node into the Products folder in the tree. The node + -- Plug in the product node into the Products folder in the tree. The node -- was built in xcode.prepareWorkspace() in xcode_common.lua; it contains IDs -- that are necessary for inter-project dependencies node = tree.insert(tr.products, prj.xcode.projectnode) diff --git a/src/_premake_init.lua b/src/_premake_init.lua index 9da7acb9..0ab14664 100644 --- a/src/_premake_init.lua +++ b/src/_premake_init.lua @@ -1110,7 +1110,7 @@ tokens = true, } - api.register { + api.register { name = "usingdirs", scope = "config", kind = "list:directory", diff --git a/src/actions/make/make_csharp.lua b/src/actions/make/make_csharp.lua index f629ee95..6145ab5e 100644 --- a/src/actions/make/make_csharp.lua +++ b/src/actions/make/make_csharp.lua @@ -94,9 +94,9 @@ function cs.getresourcefilename(cfg, fname) if path.getextension(fname) == ".resx" then - local name = cfg.buildtarget.basename .. "." - local dir = path.getdirectory(fname) - if dir ~= "." then + local name = cfg.buildtarget.basename .. "." + local dir = path.getdirectory(fname) + if dir ~= "." then name = name .. path.translate(dir, ".") .. "." end return "$(OBJDIR)/" .. p.esc(name .. path.getbasename(fname)) .. ".resources" diff --git a/src/base/api.lua b/src/base/api.lua index 659290a2..bbac5130 100755 --- a/src/base/api.lua +++ b/src/base/api.lua @@ -318,12 +318,12 @@ -- The alias name (another string value). --- - function api.alias(original, alias) - p.alias(_G, original, alias) - if _G["remove" .. original] then - p.alias(_G, "remove" .. original, "remove" .. alias) - end - end + function api.alias(original, alias) + p.alias(_G, original, alias) + if _G["remove" .. original] then + p.alias(_G, "remove" .. original, "remove" .. alias) + end + end diff --git a/src/base/config.lua b/src/base/config.lua index 879a5fe2..ed9044d0 100755 --- a/src/base/config.lua +++ b/src/base/config.lua @@ -231,7 +231,7 @@ -- An array containing the requested link target information. -- - function config.getlinks(cfg, kind, part, linkage) + function config.getlinks(cfg, kind, part, linkage) local result = {} -- If I'm building a list of link directories, include libdirs diff --git a/src/base/path.lua b/src/base/path.lua index 28aa8b3f..8616e33d 100644 --- a/src/base/path.lua +++ b/src/base/path.lua @@ -90,7 +90,7 @@ -- function path.getextension(p) - p = path.getname(p) + p = path.getname(p) local i = p:findlast(".", true) if (i) then return p:sub(i) diff --git a/src/base/project.lua b/src/base/project.lua index 48ae00bb..734c2dbc 100755 --- a/src/base/project.lua +++ b/src/base/project.lua @@ -190,9 +190,9 @@ for cfg in project.eachconfig(prj) do if not depsOnly then for _, link in ipairs(cfg.links) do - if link ~= prj.name then - add_to_project_list(cfg, link, result) - end + if link ~= prj.name then + add_to_project_list(cfg, link, result) + end end end if not linkOnly then diff --git a/src/host/os_islink.c b/src/host/os_islink.c index 4ce0902d..ee3a2089 100644 --- a/src/host/os_islink.c +++ b/src/host/os_islink.c @@ -31,10 +31,10 @@ int os_islink(lua_State* L) #else { struct stat buf; - if (lstat(path, &buf) == 0) { - lua_pushboolean(L, S_ISLNK(buf.st_mode)); - return 1; - } + if (lstat(path, &buf) == 0) { + lua_pushboolean(L, S_ISLNK(buf.st_mode)); + return 1; + } } #endif diff --git a/src/host/os_stat.c b/src/host/os_stat.c index 03d70a46..64cfe42a 100644 --- a/src/host/os_stat.c +++ b/src/host/os_stat.c @@ -13,7 +13,7 @@ int os_stat(lua_State* L) struct stat s; const char* filename = luaL_checkstring(L, 1); - if (stat(filename, &s) != 0) + if (stat(filename, &s) != 0) { lua_pushnil(L); switch (errno) diff --git a/src/host/premake.c b/src/host/premake.c index 86449d4f..949a4b51 100644 --- a/src/host/premake.c +++ b/src/host/premake.c @@ -501,8 +501,8 @@ static int run_premake_main(lua_State* L, const char* script) * argument allowed as an override. Debug builds will look at the * local file system first, then fall back to embedded. */ #if defined(NDEBUG) - int z = premake_test_file(L, script, - TEST_SCRIPTS | TEST_EMBEDDED); + int z = premake_test_file(L, script, + TEST_SCRIPTS | TEST_EMBEDDED); #else int z = premake_test_file(L, script, TEST_LOCAL | TEST_SCRIPTS | TEST_PATH | TEST_EMBEDDED); @@ -529,10 +529,10 @@ static int run_premake_main(lua_State* L, const char* script) * contents of the file's script. */ - const buildin_mapping* premake_find_embedded_script(const char* filename) - { +const buildin_mapping* premake_find_embedded_script(const char* filename) +{ #if !defined(PREMAKE_NO_BUILTIN_SCRIPTS) - int i; + int i; for (i = 0; builtin_scripts[i].name != NULL; ++i) { if (strcmp(builtin_scripts[i].name, filename) == 0) { return builtin_scripts + i; @@ -540,7 +540,7 @@ static int run_premake_main(lua_State* L, const char* script) } #endif return NULL; - } +} diff --git a/src/tools/dotnet.lua b/src/tools/dotnet.lua index 18b06ed1..af33ba6e 100644 --- a/src/tools/dotnet.lua +++ b/src/tools/dotnet.lua @@ -123,7 +123,7 @@ if fcfg.buildaction == "Component" or fcfg.buildaction == "Form" or fcfg.buildaction == "UserControl" - then + then info.SubType = fcfg.buildaction end diff --git a/src/tools/gcc.lua b/src/tools/gcc.lua index df8997f2..615c65b2 100644 --- a/src/tools/gcc.lua +++ b/src/tools/gcc.lua @@ -438,7 +438,7 @@ if #static_syslibs > 1 then table.insert(static_syslibs, "-Wl,-Bdynamic") move(static_syslibs, result) - end + end move(shared_syslibs, result) return result diff --git a/tests/actions/make/cpp/test_clang.lua b/tests/actions/make/cpp/test_clang.lua index 3410b26a..f8cb1e0d 100644 --- a/tests/actions/make/cpp/test_clang.lua +++ b/tests/actions/make/cpp/test_clang.lua @@ -41,6 +41,6 @@ ifeq ($(config),debug) ifeq ($(origin AR), default) AR = ar endif - ]] + ]] end diff --git a/tests/actions/make/cpp/test_file_rules.lua b/tests/actions/make/cpp/test_file_rules.lua index 17647d3f..0462a370 100644 --- a/tests/actions/make/cpp/test_file_rules.lua +++ b/tests/actions/make/cpp/test_file_rules.lua @@ -52,7 +52,7 @@ else endif $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" - ]] + ]] end @@ -81,7 +81,7 @@ else endif $(SILENT) $(CXX) $(ALL_CXXFLAGS) $(FORCE_INCLUDE) -o "$@" -MF "$(@:%.o=%.d)" -c "$<" - ]] + ]] end diff --git a/tests/actions/make/cpp/test_make_linking.lua b/tests/actions/make/cpp/test_make_linking.lua index 4d13597e..ebd8de61 100644 --- a/tests/actions/make/cpp/test_make_linking.lua +++ b/tests/actions/make/cpp/test_make_linking.lua @@ -153,38 +153,38 @@ -- Check a linking to a sibling shared library using -l and -L. -- - function suite.links_onSiblingSharedLib() - links "MyProject2" - flags { "RelativeLinks" } + function suite.links_onSiblingSharedLib() + links "MyProject2" + flags { "RelativeLinks" } - test.createproject(wks) - kind "SharedLib" - location "build" + test.createproject(wks) + kind "SharedLib" + location "build" - prepare { "ldFlags", "libs", "ldDeps" } - test.capture [[ + prepare { "ldFlags", "libs", "ldDeps" } + test.capture [[ ALL_LDFLAGS += $(LDFLAGS) -Lbuild/bin/Debug -Wl,-rpath,'$$ORIGIN/../../build/bin/Debug' -s LIBS += -lMyProject2 LDDEPS += build/bin/Debug/libMyProject2.so - ]] - end + ]] + end - function suite.links_onMacOSXSiblingSharedLib() - _TARGET_OS = "macosx" - links "MyProject2" + function suite.links_onMacOSXSiblingSharedLib() + _TARGET_OS = "macosx" + links "MyProject2" flags { "RelativeLinks" } - test.createproject(wks) - kind "SharedLib" - location "build" + test.createproject(wks) + kind "SharedLib" + location "build" - prepare { "ldFlags", "libs", "ldDeps" } - test.capture [[ + prepare { "ldFlags", "libs", "ldDeps" } + test.capture [[ ALL_LDFLAGS += $(LDFLAGS) -Lbuild/bin/Debug -Wl,-rpath,'@loader_path/../../build/bin/Debug' -Wl,-x LIBS += -lMyProject2 LDDEPS += build/bin/Debug/libMyProject2.dylib - ]] - end + ]] + end -- -- Check a linking multiple siblings. diff --git a/tests/actions/make/cpp/test_objects.lua b/tests/actions/make/cpp/test_objects.lua index 801c61ee..5b8a6bf4 100644 --- a/tests/actions/make/cpp/test_objects.lua +++ b/tests/actions/make/cpp/test_objects.lua @@ -37,7 +37,7 @@ OBJECTS := \ $(OBJDIR)/hello.o \ - ]] + ]] end @@ -52,7 +52,7 @@ OBJECTS := \ OBJECTS := \ $(OBJDIR)/hello.o \ - ]] + ]] end @@ -85,7 +85,7 @@ ifeq ($(config),release) endif - ]] + ]] end @@ -101,7 +101,7 @@ OBJECTS := \ $(OBJDIR)/hello.o \ $(OBJDIR)/hello1.o \ - ]] + ]] end diff --git a/tests/actions/make/cpp/test_target_rules.lua b/tests/actions/make/cpp/test_target_rules.lua index f8fb3cc0..0009193c 100644 --- a/tests/actions/make/cpp/test_target_rules.lua +++ b/tests/actions/make/cpp/test_target_rules.lua @@ -35,7 +35,7 @@ test.capture [[ all: prebuild prelink $(TARGET) @: - ]] + ]] end @@ -53,5 +53,5 @@ all: prebuild prelink $(TARGET) $(dir $(TARGETDIR))PkgInfo $(dir $(TARGETDIR))In $(dir $(TARGETDIR))PkgInfo: $(dir $(TARGETDIR))Info.plist: - ]] + ]] end diff --git a/tests/actions/make/cpp/test_tools.lua b/tests/actions/make/cpp/test_tools.lua index 80ebd4f6..6b5a0831 100644 --- a/tests/actions/make/cpp/test_tools.lua +++ b/tests/actions/make/cpp/test_tools.lua @@ -31,5 +31,5 @@ make.cppTools(cfg, p.tools.gcc) test.capture [[ RESCOMP = windres - ]] + ]] end diff --git a/tests/actions/make/cpp/test_wiidev.lua b/tests/actions/make/cpp/test_wiidev.lua index 54a6113e..063e517d 100644 --- a/tests/actions/make/cpp/test_wiidev.lua +++ b/tests/actions/make/cpp/test_wiidev.lua @@ -32,7 +32,7 @@ make.cppFlags(cfg, p.tools.gcc) test.capture [[ ALL_CPPFLAGS += $(CPPFLAGS) -MMD -MP -I$(LIBOGC_INC) $(MACHDEP) $(DEFINES) $(INCLUDES) - ]] + ]] end function suite.writesCorrectLinkerFlags() diff --git a/tests/actions/make/cs/test_embed_files.lua b/tests/actions/make/cs/test_embed_files.lua index 36b8d141..79978939 100644 --- a/tests/actions/make/cs/test_embed_files.lua +++ b/tests/actions/make/cs/test_embed_files.lua @@ -38,8 +38,8 @@ EMBEDFILES += \ $(OBJDIR)/MyProject.Hello.resources \ - ]] - end + ]] + end -- @@ -53,8 +53,8 @@ EMBEDFILES += \ EMBEDFILES += \ $(OBJDIR)/MyProject.Hello.resources \ - ]] - end + ]] + end -- @@ -71,5 +71,5 @@ EMBEDFILES += \ EMBEDFILES += \ Hello.txt \ - ]] - end + ]] + end diff --git a/tests/actions/make/cs/test_flags.lua b/tests/actions/make/cs/test_flags.lua index ac22a2c3..5717e315 100644 --- a/tests/actions/make/cs/test_flags.lua +++ b/tests/actions/make/cs/test_flags.lua @@ -35,8 +35,8 @@ prepare() test.capture [[ FLAGS = /noconfig - ]] - end + ]] + end -- @@ -48,8 +48,8 @@ prepare() test.capture [[ FLAGS = /unsafe /noconfig - ]] - end + ]] + end -- @@ -61,5 +61,5 @@ prepare() test.capture [[ FLAGS = /noconfig /win32icon:"MyProject.ico" - ]] - end + ]] + end diff --git a/tests/actions/make/cs/test_links.lua b/tests/actions/make/cs/test_links.lua index 6116eb40..cc32b613 100644 --- a/tests/actions/make/cs/test_links.lua +++ b/tests/actions/make/cs/test_links.lua @@ -5,56 +5,56 @@ -- local p = premake - local suite = test.declare("make_cs_links") - local make = p.make - local cs = p.make.cs - local project = p.project + local suite = test.declare("make_cs_links") + local make = p.make + local cs = p.make.cs + local project = p.project -- -- Setup -- - local wks, prj + local wks, prj - function suite.setup() - wks, prj = test.createWorkspace() - end + function suite.setup() + wks, prj = test.createWorkspace() + end - local function prepare() - local cfg = test.getconfig(prj, "Debug") - make.csLinkCmd(cfg, p.tools.dotnet) - end + local function prepare() + local cfg = test.getconfig(prj, "Debug") + make.csLinkCmd(cfg, p.tools.dotnet) + end -- -- Should return an empty assignment if nothing has been specified. -- - function suite.isEmptyAssignment_onNoSettings() - prepare() - test.capture [[ + function suite.isEmptyAssignment_onNoSettings() + prepare() + test.capture [[ DEPENDS = - ]] - end + ]] + end -- -- Files that can be compiled should be listed here. -- - function suite.doesListLinkDependencyFiles() - links { "MyProject2", "MyProject3" } + function suite.doesListLinkDependencyFiles() + links { "MyProject2", "MyProject3" } - test.createproject(wks) - kind "SharedLib" - language "C#" + test.createproject(wks) + kind "SharedLib" + language "C#" - test.createproject(wks) - kind "SharedLib" - language "C#" + test.createproject(wks) + kind "SharedLib" + language "C#" - prepare () - test.capture [[ + prepare () + test.capture [[ DEPENDS = bin/Debug/MyProject2.dll bin/Debug/MyProject3.dll - ]] - end + ]] + end diff --git a/tests/actions/make/cs/test_sources.lua b/tests/actions/make/cs/test_sources.lua index 0789c6c9..3021bb37 100644 --- a/tests/actions/make/cs/test_sources.lua +++ b/tests/actions/make/cs/test_sources.lua @@ -38,8 +38,8 @@ SOURCES += \ Hello.cs \ - ]] - end + ]] + end -- -- Path delimiter uses slash instead of backslash @@ -68,8 +68,8 @@ SOURCES += \ SOURCES += \ Hello.cs \ - ]] - end + ]] + end -- @@ -86,5 +86,5 @@ SOURCES += \ SOURCES += \ Hello.txt \ - ]] - end + ]] + end diff --git a/tests/actions/vstudio/vc2010/test_build_log.lua b/tests/actions/vstudio/vc2010/test_build_log.lua index c585f8c8..1c1a2d6b 100644 --- a/tests/actions/vstudio/vc2010/test_build_log.lua +++ b/tests/actions/vstudio/vc2010/test_build_log.lua @@ -44,7 +44,7 @@ function suite.writesPathIfSet() buildlog "logs/MyCustomLogFile.log" prepare() - test.capture [[ + test.capture [[ logs\MyCustomLogFile.log diff --git a/tests/base/test_configset.lua b/tests/base/test_configset.lua index e65737a7..e7141128 100644 --- a/tests/base/test_configset.lua +++ b/tests/base/test_configset.lua @@ -127,9 +127,9 @@ -- List fields should return an empty list of not set. -- - function suite.lists_returnsEmptyTable_onNotSet() - test.isequal({}, configset.fetch(cset, field.get("buildoptions"), {})) - end + function suite.lists_returnsEmptyTable_onNotSet() + test.isequal({}, configset.fetch(cset, field.get("buildoptions"), {})) + end -- diff --git a/tests/base/test_path.lua b/tests/base/test_path.lua index 0f3879f9..bdef3866 100755 --- a/tests/base/test_path.lua +++ b/tests/base/test_path.lua @@ -147,7 +147,7 @@ test.isequal("", path.getextension("filename")) end - function suite.getextension_ReturnsEmptyString_OnPathWithDotAndNoExtension() + function suite.getextension_ReturnsEmptyString_OnPathWithDotAndNoExtension() test.isequal("", path.getextension("/.premake/premake")) end @@ -155,7 +155,7 @@ test.isequal(".txt", path.getextension("filename.txt")) end - function suite.getextension_ReturnsExtension_OnPathWithDot() + function suite.getextension_ReturnsExtension_OnPathWithDot() test.isequal(".lua", path.getextension("/.premake/premake.lua")) end @@ -222,7 +222,7 @@ end function suite.getrelative_ignoresTrailingSlashes() - test.isequal("c", path.getrelative("/a/b/","/a/b/c")) + test.isequal("c", path.getrelative("/a/b/","/a/b/c")) end function suite.getrelative_returnsAbsPath_onContactWithFileSysRoot() @@ -410,19 +410,19 @@ end function suite.getabsolute_replaceExtensionWithDotMultipleDots() - test.isequal("/nunit.framework.foo", path.replaceextension("/nunit.framework.dll",".foo")) + test.isequal("/nunit.framework.foo", path.replaceextension("/nunit.framework.dll",".foo")) end function suite.getabsolute_replaceExtensionCompletePath() - test.isequal("/nunit/framework/main.foo", path.replaceextension("/nunit/framework/main.cpp",".foo")) + test.isequal("/nunit/framework/main.foo", path.replaceextension("/nunit/framework/main.cpp",".foo")) end function suite.getabsolute_replaceExtensionWithoutExtension() - test.isequal("/nunit/framework/main.foo", path.replaceextension("/nunit/framework/main",".foo")) + test.isequal("/nunit/framework/main.foo", path.replaceextension("/nunit/framework/main",".foo")) end - function suite.getabsolute_replaceExtensionWithEmptyString() - test.isequal("foo", path.replaceextension("foo.lua","")) + function suite.getabsolute_replaceExtensionWithEmptyString() + test.isequal("foo", path.replaceextension("foo.lua","")) end diff --git a/tests/oven/test_filtering.lua b/tests/oven/test_filtering.lua index a9906a5b..a5ebdffa 100644 --- a/tests/oven/test_filtering.lua +++ b/tests/oven/test_filtering.lua @@ -21,7 +21,7 @@ local function prepare() wks = test.getWorkspace(wks) prj = test.getproject(wks, 1) - cfg = test.getconfig(prj, "Debug") + cfg = test.getconfig(prj, "Debug") end diff --git a/tests/project/test_vpaths.lua b/tests/project/test_vpaths.lua index 63a58d8d..e1b6173e 100644 --- a/tests/project/test_vpaths.lua +++ b/tests/project/test_vpaths.lua @@ -124,11 +124,11 @@ test.isequal("Headers/myproject/hello.h", run()) end - function suite.matchBaseFileName_onWildcardExtension() - files { "hello.cpp" } - vpaths { ["Sources"] = "hello.*" } - test.isequal("Sources/hello.cpp", run()) - end + function suite.matchBaseFileName_onWildcardExtension() + files { "hello.cpp" } + vpaths { ["Sources"] = "hello.*" } + test.isequal("Sources/hello.cpp", run()) + end -- From 1e648f55151c01c15a2db220f56eb6bf9b189548 Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Wed, 26 Apr 2017 15:59:20 -0700 Subject: [PATCH 49/59] [core] Adding ARM support for Visual Studio. --- src/_premake_init.lua | 1 + src/actions/vstudio/_vstudio.lua | 1 + src/actions/vstudio/vs2010_vcxproj.lua | 8 ++++++++ src/base/_foundation.lua | 1 + 4 files changed, 11 insertions(+) diff --git a/src/_premake_init.lua b/src/_premake_init.lua index 0ab14664..0a49df62 100644 --- a/src/_premake_init.lua +++ b/src/_premake_init.lua @@ -26,6 +26,7 @@ "universal", p.X86, p.X86_64, + p.ARM, }, aliases = { i386 = p.X86, diff --git a/src/actions/vstudio/_vstudio.lua b/src/actions/vstudio/_vstudio.lua index a29a2d0e..7375a218 100644 --- a/src/actions/vstudio/_vstudio.lua +++ b/src/actions/vstudio/_vstudio.lua @@ -24,6 +24,7 @@ x86 = "x86", x86_64 = "x64", xbox360 = "Xbox 360", + ARM = "ARM", } vstudio.vs2010_architectures = diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index b4a0bf33..9d08315f 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -159,6 +159,7 @@ m.platformToolset, m.wholeProgramOptimization, m.nmakeOutDirs, + m.windowsSDKDesktopARMSupport, } end end @@ -1792,6 +1793,13 @@ end + function m.windowsSDKDesktopARMSupport(cfg) + if cfg.architecture == p.ARM then + p.w('true') + end + end + + function m.nmakeOutput(cfg) m.element("NMakeOutput", nil, "$(OutDir)%s", cfg.buildtarget.name) end diff --git a/src/base/_foundation.lua b/src/base/_foundation.lua index 5f233abe..1a617a4c 100644 --- a/src/base/_foundation.lua +++ b/src/base/_foundation.lua @@ -53,6 +53,7 @@ premake.WINDOWS = "windows" premake.X86 = "x86" premake.X86_64 = "x86_64" + premake.ARM = "ARM" premake.XBOX360 = "xbox360" From 43da317fe89a95c3148683f494eacdbc3f842a3e Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Thu, 27 Apr 2017 20:47:33 +1000 Subject: [PATCH 50/59] Removed echo off in VS rules prop generator --- src/actions/vstudio/vs2010_rules_props.lua | 2 +- tests/actions/vstudio/vc2010/test_rule_props.lua | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/actions/vstudio/vs2010_rules_props.lua b/src/actions/vstudio/vs2010_rules_props.lua index 8923af87..450660d5 100644 --- a/src/actions/vstudio/vs2010_rules_props.lua +++ b/src/actions/vstudio/vs2010_rules_props.lua @@ -152,7 +152,7 @@ if buildcommands and #buildcommands > 0 then local cmds = os.translateCommands(buildcommands, p.WINDOWS) cmds = table.concat(cmds, p.eol()) - p.x('@echo off\n%s', cmds) + p.x('%s', cmds) end end diff --git a/tests/actions/vstudio/vc2010/test_rule_props.lua b/tests/actions/vstudio/vc2010/test_rule_props.lua index b5f34ea7..8b61eec2 100644 --- a/tests/actions/vstudio/vc2010/test_rule_props.lua +++ b/tests/actions/vstudio/vc2010/test_rule_props.lua @@ -51,8 +51,7 @@ m.commandLineTemplates(r) test.capture [[ -@echo off -package-example-compiler.exe [output_path] "%(Identity)" +package-example-compiler.exe [output_path] "%(Identity)" ]] end From 2c74dbee95c59534fa5ec7114f8cf2ee5ecec857 Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Thu, 27 Apr 2017 16:13:59 -0700 Subject: [PATCH 51/59] [core] get file/line information on deprecated API's. --- src/base/_foundation.lua | 16 ++++++++++++++++ src/base/api.lua | 20 +++++++++++++------- src/base/os.lua | 6 ++++-- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/base/_foundation.lua b/src/base/_foundation.lua index 1a617a4c..74b5da83 100644 --- a/src/base/_foundation.lua +++ b/src/base/_foundation.lua @@ -376,3 +376,19 @@ print(string.format(msg, ...)) end end + + +-- +-- make a string from debug.getinfo information. +-- + function filelineinfo(level) + local info = debug.getinfo(level+1, "Sl") + if info == nil then + return nil + end + if info.what == "C" then + return "C function" + else + return string.format("%s(%d)", info.short_src, info.currentline) + end + end diff --git a/src/base/api.lua b/src/base/api.lua index bbac5130..e1d7fac0 100755 --- a/src/base/api.lua +++ b/src/base/api.lua @@ -490,8 +490,12 @@ if field.deprecated and type(field.deprecated.handler) == "function" then field.deprecated.handler(value) if field.deprecated.message and api._deprecations ~= "off" then - p.warnOnce(field.name, "the field %s has been deprecated and will be removed.\n %s", field.name, field.deprecated.message) - if api._deprecations == "error" then error("deprecation errors enabled", 3) end + local caller = filelineinfo(2) + local key = field.name .. "_" .. caller + p.warnOnce(key, "the field %s has been deprecated and will be removed.\n %s\n @%s\n", field.name, field.deprecated.message, caller) + if api._deprecations == "error" then + error("deprecation errors enabled", 3) + end end end @@ -536,13 +540,14 @@ local removes = {} - function check(value) + local function check(value) if field.deprecated[value] then local handler = field.deprecated[value] if handler.remove then handler.remove(value) end if handler.message and api._deprecations ~= "off" then - local key = field.name .. "_" .. value - p.warnOnce(key, "the %s value %s has been deprecated and will be removed.\n %s", field.name, value, handler.message) + local caller = filelineinfo(8) + local key = field.name .. "_" .. value .. "_" .. caller + p.warnOnce(key, "the %s value %s has been deprecated and will be removed.\n %s\n @%s\n", field.name, value, handler.message, caller) if api._deprecations == "error" then error { msg="deprecation errors enabled" } end @@ -647,8 +652,9 @@ local handler = field.deprecated[canonical] handler.add(canonical) if handler.message and api._deprecations ~= "off" then - local key = field.name .. "_" .. value - p.warnOnce(key, "the %s value %s has been deprecated and will be removed.\n %s", field.name, canonical, handler.message) + local caller = filelineinfo(9) + local key = field.name .. "_" .. value .. "_" .. caller + p.warnOnce(key, "the %s value %s has been deprecated and will be removed.\n %s\n @%s\n", field.name, canonical, handler.message, caller) if api._deprecations == "error" then return nil, "deprecation errors enabled" end diff --git a/src/base/os.lua b/src/base/os.lua index ebb59b6a..43ed5f6d 100644 --- a/src/base/os.lua +++ b/src/base/os.lua @@ -143,7 +143,8 @@ end function os.get() - premake.warnOnce("os.get", "os.get() is deprecated, use 'os.target()' or 'os.host()'.") + local caller = filelineinfo(2) + premake.warnOnce(caller, "os.get() is deprecated, use 'os.target()' or 'os.host()'.\n @%s\n", caller) return os.target() end @@ -180,7 +181,8 @@ end function os.is(id) - premake.warnOnce("os.is", "os.is() is deprecated, use 'os.istarget()' or 'os.ishost()'.") + local caller = filelineinfo(2) + premake.warnOnce(caller, "os.is() is deprecated, use 'os.istarget()' or 'os.ishost()'.\n @%s\n", caller) return os.istarget(id) end From 6e175f026ae73221dddf4f93c5e27bf2612a71f3 Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Thu, 27 Apr 2017 16:12:51 -0700 Subject: [PATCH 52/59] [core] Print warnings in purple --- src/base/_foundation.lua | 3 +++ src/host/premake.c | 7 +++++++ src/host/premake.h | 2 ++ src/host/term_textColor.c | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+) create mode 100644 src/host/term_textColor.c diff --git a/src/base/_foundation.lua b/src/base/_foundation.lua index 74b5da83..bd98b4d2 100644 --- a/src/base/_foundation.lua +++ b/src/base/_foundation.lua @@ -334,7 +334,10 @@ if _OPTIONS.fatal then error(message) else + local color = term.getTextColor(); + term.setTextColor(13); io.stderr:write(string.format("** Warning: " .. message .. "\n", ...)) + term.setTextColor(color); end end diff --git a/src/host/premake.c b/src/host/premake.c index 949a4b51..17c2273c 100644 --- a/src/host/premake.c +++ b/src/host/premake.c @@ -101,6 +101,12 @@ static const luaL_Reg buffered_functions[] = { { NULL, NULL } }; +static const luaL_Reg term_functions[] = { + { "getTextColor", term_getTextColor }, + { "setTextColor", term_setTextColor }, + { NULL, NULL } +}; + #ifdef PREMAKE_CURL static const luaL_Reg http_functions[] = { { "get", http_get }, @@ -130,6 +136,7 @@ int premake_init(lua_State* L) luaL_register(L, "os", os_functions); luaL_register(L, "string", string_functions); luaL_register(L, "buffered", buffered_functions); + luaL_register(L, "term", term_functions); #ifdef PREMAKE_CURL luaL_register(L, "http", http_functions); diff --git a/src/host/premake.h b/src/host/premake.h index 562d11a5..98f6df29 100644 --- a/src/host/premake.h +++ b/src/host/premake.h @@ -134,6 +134,8 @@ int buffered_write(lua_State* L); int buffered_writeln(lua_State* L); int buffered_close(lua_State* L); int buffered_tostring(lua_State* L); +int term_getTextColor(lua_State* L); +int term_setTextColor(lua_State* L); #ifdef PREMAKE_CURL int http_get(lua_State* L); diff --git a/src/host/term_textColor.c b/src/host/term_textColor.c new file mode 100644 index 00000000..20e5e0a7 --- /dev/null +++ b/src/host/term_textColor.c @@ -0,0 +1,39 @@ +/** + * \file term_textColor.c + * \brief Change the foreground color of the terminal output. + * \author Copyright (c) 2017 Blizzard Entertainment and the Premake project + */ + +#include "premake.h" + + +int term_getTextColor(lua_State* L) +{ +#if PLATFORM_WINDOWS + CONSOLE_SCREEN_BUFFER_INFO info; + if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info)) + return 0; + lua_pushinteger(L, (int)info.wAttributes); + return 1; +#else + (void)(L); /* warning: unused parameter */ + return 0; +#endif +} + + +int term_setTextColor(lua_State* L) +{ +#if PLATFORM_WINDOWS + lua_Integer color = luaL_optinteger(L, 1, -1); + if (color >= 0) + { + SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), (WORD)color); + SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), (WORD)color); + } +#else + (void)(L); /* warning: unused parameter */ +#endif + + return 0; + } From ee0b66acf48e8f9c2f355a961181a4835aa1abbd Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Mon, 1 May 2017 09:14:31 -0700 Subject: [PATCH 53/59] add 'term.warningColor' and some other useful term tools. --- src/_manifest.lua | 1 + src/base/_foundation.lua | 5 ++--- src/base/term.lua | 44 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 src/base/term.lua diff --git a/src/_manifest.lua b/src/_manifest.lua index 79ad7974..b8dc56bf 100644 --- a/src/_manifest.lua +++ b/src/_manifest.lua @@ -25,6 +25,7 @@ "base/json.lua", "base/jsonwrapper.lua", "base/languages.lua", + "base/term.lua", -- configuration data "base/field.lua", diff --git a/src/base/_foundation.lua b/src/base/_foundation.lua index bd98b4d2..9bff9def 100644 --- a/src/base/_foundation.lua +++ b/src/base/_foundation.lua @@ -334,10 +334,9 @@ if _OPTIONS.fatal then error(message) else - local color = term.getTextColor(); - term.setTextColor(13); + term.pushColor(term.warningColor) io.stderr:write(string.format("** Warning: " .. message .. "\n", ...)) - term.setTextColor(color); + term.popColor(); end end diff --git a/src/base/term.lua b/src/base/term.lua new file mode 100644 index 00000000..c99cac86 --- /dev/null +++ b/src/base/term.lua @@ -0,0 +1,44 @@ +-- +-- term.lua +-- Additions to the 'term' namespace. +-- Copyright (c) 2017 Blizzard Entertainment and the Premake project +-- + +-- default colors. +term.black = 0 +term.blue = 1 +term.green = 2 +term.cyan = 3 +term.red = 4 +term.purple = 5 +term.brown = 6 +term.lightGray = 7 +term.gray = 8 +term.lightBlue = 9 +term.lightGreen = 10 +term.lightCyan = 11 +term.lightRed = 12 +term.magenta = 13 +term.yellow = 14 +term.white = 15 + +-- colors for specific purpose. +term.warningColor = term.magenta +term.errorColor = term.lightRed + +-- color stack implementation. +term._colorStack = {} + +function term.pushColor(color) + local old = term.getTextColor() + table.insert(term._colorStack, old) + + term.setTextColor(color) +end + +function term.popColor() + if #term._colorStack > 0 then + local color = table.remove(term._colorStack) + term.setTextColor(color) + end +end From 0c1d4e10ae10da7e2ef1c912dbf0c7cd54caddb1 Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Thu, 27 Apr 2017 13:57:11 -0700 Subject: [PATCH 54/59] [core] Fix Visual Studio ExecutablePath settings. --- src/actions/vstudio/vs2010_vcxproj.lua | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index 9d08315f..0d32112a 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -1875,6 +1875,12 @@ function m.executablePath(cfg) local dirs = vstudio.path(cfg, cfg.bindirs) if #dirs > 0 then + dirs = table.translate(dirs, function(dir) + if path.isabsolute(dir) then + return dir + end + return "$(ProjectDir)" .. dir + end) m.element("ExecutablePath", nil, "%s;$(ExecutablePath)", table.concat(dirs, ";")) end end From bce3f2c4ed1f54aa2b46ea395d12e554d98e6221 Mon Sep 17 00:00:00 2001 From: "R. Blaine Whittle" Date: Tue, 18 Apr 2017 09:37:29 -0700 Subject: [PATCH 55/59] [core] new cmd path decorations with %[] syntax this is for marking cmd options as paths relative to the projects base dir. decorated paths can use tokens / macros decorated paths are wrapped with "". Final slashes are honored. Slashes are platform specific. Note that the working dir for custom cmd is undefined as the current working dir will be different between xcode (wks.location) and visual studio / make (prj.location.) Changing the CWD isn't a good default behavior (for reasons.) This leads to prior use of premake requiring alot of string concating / function calls for path translations which make the cmd line difficult to read and maintain. With path decorations, one can just make those relative paths with %[] and everything should work. --- src/actions/make/_make.lua | 2 +- src/actions/make/make_cpp.lua | 2 +- src/actions/make/make_makefile.lua | 4 +-- src/actions/vstudio/vs2005_csproj.lua | 2 +- src/actions/vstudio/vs200x_vcproj.lua | 8 ++--- src/actions/vstudio/vs2010_vcxproj.lua | 6 ++-- src/base/os.lua | 41 ++++++++++++++++++++++++++ tests/base/test_os.lua | 15 ++++++++++ 8 files changed, 68 insertions(+), 12 deletions(-) diff --git a/src/actions/make/_make.lua b/src/actions/make/_make.lua index d9c5d85b..585fa913 100644 --- a/src/actions/make/_make.lua +++ b/src/actions/make/_make.lua @@ -256,7 +256,7 @@ local steps = cfg[event .. "commands"] local msg = cfg[event .. "message"] if #steps > 0 then - steps = os.translateCommands(steps) + steps = os.translateCommandsAndPaths(steps, cfg.project.basedir, cfg.project.location) msg = msg or string.format("Running %s commands", event) _p('\t@echo %s', msg) _p('\t%s', table.implode(steps, "", "", "\n\t")) diff --git a/src/actions/make/make_cpp.lua b/src/actions/make/make_cpp.lua index fb3a227f..aa3cb432 100644 --- a/src/actions/make/make_cpp.lua +++ b/src/actions/make/make_cpp.lua @@ -178,7 +178,7 @@ _p('%s: %s', output, dependencies) _p('\t@echo "%s"', filecfg.buildmessage or ("Building " .. filecfg.relpath)) - local cmds = os.translateCommands(filecfg.buildcommands) + local cmds = os.translateCommandsAndPaths(filecfg.buildcommands, cfg.project.basedir, cfg.project.location) for _, cmd in ipairs(cmds) do if cfg.bindirs and #cfg.bindirs > 0 then _p('\t$(SILENT) $(EXE_PATHS) %s', cmd) diff --git a/src/actions/make/make_makefile.lua b/src/actions/make/make_makefile.lua index 739995b0..e5c67bcd 100644 --- a/src/actions/make/make_makefile.lua +++ b/src/actions/make/make_makefile.lua @@ -72,7 +72,7 @@ _p(' define BUILDCMDS') local steps = cfg.buildcommands if #steps > 0 then - steps = os.translateCommands(steps) + steps = os.translateCommandsAndPaths(steps, cfg.project.basedir, cfg.project.location) _p('\t@echo Running build commands') _p('\t%s', table.implode(steps, "", "", "\n\t")) end @@ -84,7 +84,7 @@ _p(' define CLEANCMDS') local steps = cfg.cleancommands if #steps > 0 then - steps = os.translateCommands(steps) + steps = os.translateCommandsAndPaths(steps, cfg.project.basedir, cfg.project.location) _p('\t@echo Running clean commands') _p('\t%s', table.implode(steps, "", "", "\n\t")) end diff --git a/src/actions/vstudio/vs2005_csproj.lua b/src/actions/vstudio/vs2005_csproj.lua index b6d5ab01..0ce1c3f4 100644 --- a/src/actions/vstudio/vs2005_csproj.lua +++ b/src/actions/vstudio/vs2005_csproj.lua @@ -226,7 +226,7 @@ function cs2005.buildEvents(prj) local function output(name, steps) if #steps > 0 then - steps = os.translateCommands(steps, p.WINDOWS) + steps = os.translateCommandsAndPaths(steps, prj.basedir, prj.location) steps = table.implode(steps, "", "", "\r\n") _x(2,'<%sBuildEvent>%s', name, steps, name) end diff --git a/src/actions/vstudio/vs200x_vcproj.lua b/src/actions/vstudio/vs200x_vcproj.lua index e42e8cc4..43895923 100644 --- a/src/actions/vstudio/vs200x_vcproj.lua +++ b/src/actions/vstudio/vs200x_vcproj.lua @@ -945,7 +945,7 @@ function m.buildCommandLine(cfg) - local cmds = os.translateCommands(cfg.buildcommands, p.WINDOWS) + local cmds = os.translateCommandsAndPaths(cfg.buildcommands, cfg.project.basedir, cfg.project.location) p.x('BuildCommandLine="%s"', table.concat(cmds, "\r\n")) end @@ -960,7 +960,7 @@ function m.cleanCommandLine(cfg) - local cmds = os.translateCommands(cfg.cleancommands, p.WINDOWS) + local cmds = os.translateCommandsAndPaths(cfg.cleancommands, cfg.project.basedir, cfg.project.location) cmds = table.concat(cmds, "\r\n") p.x('CleanCommandLine="%s"', cmds) end @@ -975,7 +975,7 @@ if msg then p.x('Description="%s"', msg) end - steps = os.translateCommands(steps, p.WINDOWS) + steps = os.translateCommandsAndPaths(steps, cfg.project.basedir, cfg.project.location) p.x('CommandLine="%s"', table.implode(steps, "", "", "\r\n")) end end @@ -1045,7 +1045,7 @@ function m.customBuildTool(cfg) local cfg, filecfg = config.normalize(cfg) if filecfg and fileconfig.hasCustomBuildRule(filecfg) then - local cmds = os.translateCommands(filecfg.buildcommands, p.WINDOWS) + local cmds = os.translateCommandsAndPaths(filecfg.buildcommands, filecfg.project.basedir, filecfg.project.location) p.x('CommandLine="%s"', table.concat(cmds,'\r\n')) local outputs = project.getrelative(filecfg.project, filecfg.buildoutputs) diff --git a/src/actions/vstudio/vs2010_vcxproj.lua b/src/actions/vstudio/vs2010_vcxproj.lua index 9d08315f..1c6afd5d 100644 --- a/src/actions/vstudio/vs2010_vcxproj.lua +++ b/src/actions/vstudio/vs2010_vcxproj.lua @@ -511,7 +511,7 @@ local msg = cfg[field .. "message"] if #steps > 0 then - steps = os.translateCommands(steps, p.WINDOWS) + steps = os.translateCommandsAndPaths(steps, cfg.project.basedir, cfg.project.location) p.push('<%s>', name) p.x('%s', table.implode(steps, "", "", "\r\n")) if msg then @@ -1131,7 +1131,7 @@ function m.buildCommands(fcfg, condition) - local commands = os.translateCommands(fcfg.buildcommands, p.WINDOWS) + local commands = os.translateCommandsAndPaths(fcfg.buildcommands, fcfg.project.basedir, fcfg.project.location) commands = table.concat(commands,'\r\n') m.element("Command", condition, '%s', commands) end @@ -1768,7 +1768,7 @@ function m.nmakeCommandLine(cfg, commands, phase) if #commands > 0 then - commands = os.translateCommands(commands, p.WINDOWS) + commands = os.translateCommandsAndPaths(commands, cfg.project.basedir, cfg.project.location) commands = table.concat(p.esc(commands), p.eol()) p.w('%s', phase, commands, phase) end diff --git a/src/base/os.lua b/src/base/os.lua index 43ed5f6d..2ac7c323 100644 --- a/src/base/os.lua +++ b/src/base/os.lua @@ -610,6 +610,47 @@ +--- +-- Translate decorated command paths into their OS equivalents. +--- + + function os.translateCommandsAndPaths(cmds, basedir, location, map) + local translatedBaseDir = path.getrelative(location, basedir) + + map = map or os.target() + + local translateFunction = function(value) + local result = path.join(translatedBaseDir, value) + if value:endswith('/') or value:endswith('\\') or + value:endswith('/"') or value:endswith('\\"') then + result = result .. '/' + end + if map == 'windows' then + result = path.translate(result) + end + return result + end + + local processOne = function(cmd) + local replaceFunction = function(value) + value = value:sub(3, #value - 1) + return '"' .. translateFunction(value) .. '"' + end + return string.gsub(cmd, "%%%[[^%]\r\n]*%]", replaceFunction) + end + + if type(cmds) == "table" then + local result = {} + for i = 1, #cmds do + result[i] = processOne(cmds[i]) + end + return os.translateCommands(result, map) + else + return os.translateCommands(processOne(cmds), map) + end + end + + -- -- Generate a UUID. -- diff --git a/tests/base/test_os.lua b/tests/base/test_os.lua index f2414b95..37463734 100644 --- a/tests/base/test_os.lua +++ b/tests/base/test_os.lua @@ -281,3 +281,18 @@ local version = os.getversion(); test.istrue(version ~= nil) end + + + +-- +-- os.translateCommandsAndPaths. +-- + + function suite.translateCommandsAndPaths() + test.isequal('cmdtool "../foo/path1"', os.translateCommandsAndPaths("cmdtool %[path1]", '../foo', '.', 'osx')) + end + + function suite.translateCommandsAndPaths_PreserveSlash() + test.isequal('cmdtool "../foo/path1/"', os.translateCommandsAndPaths("cmdtool %[path1/]", '../foo', '.', 'osx')) + end + From fcb76a1c91acb3ce68b0ddbfe4215052cb593e0b Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Mon, 1 May 2017 14:21:49 -0700 Subject: [PATCH 56/59] [core] Don't set default entrypoint, rely on visual studio default. --- src/_premake_init.lua | 3 --- .../vstudio/vc200x/test_linker_block.lua | 3 --- .../vstudio/vc2010/test_excluded_configs.lua | 2 -- tests/actions/vstudio/vc2010/test_link.lua | 19 ++++++++++++++++--- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/_premake_init.lua b/src/_premake_init.lua index 0a49df62..f2f91c4d 100644 --- a/src/_premake_init.lua +++ b/src/_premake_init.lua @@ -1545,7 +1545,4 @@ filter { "system:macosx" } toolset "clang" - filter { "system:windows", "kind:WindowedApp or ConsoleApp" } - entrypoint "mainCRTStartup" - filter {} diff --git a/tests/actions/vstudio/vc200x/test_linker_block.lua b/tests/actions/vstudio/vc200x/test_linker_block.lua index f13520c3..3eab2b5c 100644 --- a/tests/actions/vstudio/vc200x/test_linker_block.lua +++ b/tests/actions/vstudio/vc200x/test_linker_block.lua @@ -41,7 +41,6 @@ LinkIncremental="2" GenerateDebugInformation="false" SubSystem="1" - EntryPointSymbol="mainCRTStartup" TargetMachine="1" /> ]] @@ -62,7 +61,6 @@ LinkIncremental="2" GenerateDebugInformation="false" SubSystem="2" - EntryPointSymbol="mainCRTStartup" TargetMachine="1" /> ]] @@ -138,7 +136,6 @@ LinkIncremental="2" GenerateDebugInformation="true" SubSystem="1" - EntryPointSymbol="mainCRTStartup" TargetMachine="1" /> ]] diff --git a/tests/actions/vstudio/vc2010/test_excluded_configs.lua b/tests/actions/vstudio/vc2010/test_excluded_configs.lua index 34fa07a7..3df6eb6b 100644 --- a/tests/actions/vstudio/vc2010/test_excluded_configs.lua +++ b/tests/actions/vstudio/vc2010/test_excluded_configs.lua @@ -52,7 +52,6 @@ test.capture [[ Console - mainCRTStartup ]] end @@ -71,7 +70,6 @@ Console bin\Ares\Debug\MyProject2.lib;%(AdditionalDependencies) - mainCRTStartup false diff --git a/tests/actions/vstudio/vc2010/test_link.lua b/tests/actions/vstudio/vc2010/test_link.lua index 4455d935..2a40533f 100644 --- a/tests/actions/vstudio/vc2010/test_link.lua +++ b/tests/actions/vstudio/vc2010/test_link.lua @@ -72,7 +72,6 @@ test.capture [[ Console - mainCRTStartup ]] end @@ -82,7 +81,6 @@ test.capture [[ Windows - mainCRTStartup ]] end @@ -108,6 +106,22 @@ end +-- +-- Test the handling of the entrypoint API. +-- + function suite.onEntryPoint() + kind "ConsoleApp" + entrypoint "foobar" + prepare() + test.capture [[ + + Console + foobar + + ]] + end + + -- -- Test the handling of the NoImplicitLink flag. -- @@ -508,7 +522,6 @@ test.capture [[ Console - mainCRTStartup true ]] end From f1d461f3a59e0d4e8f916fde3538cc2501ff0296 Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Tue, 2 May 2017 09:09:38 -0700 Subject: [PATCH 57/59] Add test for multiple tokens. --- tests/base/test_os.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/base/test_os.lua b/tests/base/test_os.lua index 37463734..ce5222db 100644 --- a/tests/base/test_os.lua +++ b/tests/base/test_os.lua @@ -296,3 +296,7 @@ test.isequal('cmdtool "../foo/path1/"', os.translateCommandsAndPaths("cmdtool %[path1/]", '../foo', '.', 'osx')) end + function suite.translateCommandsAndPaths_MultipleTokens() + test.isequal('cmdtool "../foo/path1" "../foo/path2/"', os.translateCommandsAndPaths("cmdtool %[path1] %[path2/]", '../foo', '.', 'osx')) + end + From 289e880b38b4a70d56d38a4310e21fc8f5f9c334 Mon Sep 17 00:00:00 2001 From: Tom van Dijck Date: Tue, 2 May 2017 09:15:42 -0700 Subject: [PATCH 58/59] Add tests for ExecutablePath. --- .../vstudio/vc2010/test_output_props.lua | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/actions/vstudio/vc2010/test_output_props.lua b/tests/actions/vstudio/vc2010/test_output_props.lua index 1b2edf6f..5ec306e9 100755 --- a/tests/actions/vstudio/vc2010/test_output_props.lua +++ b/tests/actions/vstudio/vc2010/test_output_props.lua @@ -289,3 +289,37 @@ ]] end + +-- +-- Check the handling of the VC++ ExecutablePath. +-- + + function suite.onBinDirsRelative() + bindirs { "../Include" } + prepare() + test.capture [[ + + true + bin\Debug\ + obj\Debug\ + MyProject + .exe + $(ProjectDir)..\Include;$(ExecutablePath) + + ]] + end + + function suite.onBinDirsAbsolute() + bindirs { "C:\\Include" } + prepare() + test.capture [[ + + true + bin\Debug\ + obj\Debug\ + MyProject + .exe + C:\Include;$(ExecutablePath) + + ]] + end From 43824fa22c37429bf38fefe27bd888f5e63c2f76 Mon Sep 17 00:00:00 2001 From: Sam Surtees Date: Fri, 5 May 2017 02:20:45 +1000 Subject: [PATCH 59/59] Added support at the file level for the NoPCH flag in VS200x projects --- src/actions/vstudio/vs200x_vcproj.lua | 2 ++ tests/actions/vstudio/vc200x/test_files.lua | 24 +++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/actions/vstudio/vs200x_vcproj.lua b/src/actions/vstudio/vs200x_vcproj.lua index e42e8cc4..478b0697 100644 --- a/src/actions/vstudio/vs200x_vcproj.lua +++ b/src/actions/vstudio/vs200x_vcproj.lua @@ -1609,6 +1609,8 @@ prj.system == p.WINDOWS then p.w('UsePrecompiledHeader="1"') + elseif file.flags.NoPCH then + p.w('UsePrecompiledHeader="0"') end else if not prj.flags.NoPCH and prj.pchheader then diff --git a/tests/actions/vstudio/vc200x/test_files.lua b/tests/actions/vstudio/vc200x/test_files.lua index 840c4a86..d503bcae 100644 --- a/tests/actions/vstudio/vc200x/test_files.lua +++ b/tests/actions/vstudio/vc200x/test_files.lua @@ -205,6 +205,30 @@ end +-- +-- A file flagged with NoPCH should be marked as such. +-- + + function suite.useNoPCHFlag() + files { "test.cpp" } + filter { "files:test.cpp" } + flags { "NoPCH" } + prepare() + test.capture [[ + + + +