diff --git a/src/beast/Builds/VisualStudio2012/beast.vcxproj b/src/beast/Builds/VisualStudio2012/beast.vcxproj index 6f9e5f3c3c..f55e325993 100644 --- a/src/beast/Builds/VisualStudio2012/beast.vcxproj +++ b/src/beast/Builds/VisualStudio2012/beast.vcxproj @@ -21,9 +21,18 @@ + + + + + + + + + - + true true true @@ -69,14 +78,27 @@ + + + + + + + + + + + + + @@ -90,6 +112,16 @@ + + + + + + + + + + @@ -104,6 +136,7 @@ + @@ -127,8 +160,6 @@ - - @@ -186,7 +217,6 @@ - @@ -203,7 +233,6 @@ - @@ -213,8 +242,6 @@ - - @@ -222,8 +249,6 @@ - - @@ -249,7 +274,6 @@ - @@ -258,31 +282,20 @@ - - - + - - - - - - - - - @@ -371,6 +384,49 @@ + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + + + true + true + true + true + true true @@ -378,6 +434,19 @@ true + + true + true + true + true + + + true + true + true + true + + true true @@ -456,18 +525,6 @@ true true - - true - true - true - true - - - true - true - true - true - true true @@ -941,12 +998,6 @@ true true - - true - true - true - true - true true @@ -1001,12 +1052,6 @@ true true - - true - true - true - true - true true @@ -1025,12 +1070,6 @@ true true - - true - true - true - true - true true diff --git a/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters b/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters index b725af4e99..b0278d174b 100644 --- a/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters +++ b/src/beast/Builds/VisualStudio2012/beast.vcxproj.filters @@ -1,9 +1,6 @@  - - beast_core - beast_core\native @@ -40,6 +37,36 @@ _meta + + beast\http\impl\http-parser + + + beast\http\impl\http-parser + + + beast\http\impl\http-parser + + + beast\http\impl\http-parser + + + beast\http\impl\http-parser + + + beast\http\impl\http-parser + + + beast\http\impl\http-parser + + + beast\http\impl\http-parser + + + beast\http\impl\http-parser + + + beast_core + @@ -174,9 +201,6 @@ {5904368f-a0f2-4d26-a031-8cbe4448dc3f} - - {ac367054-ddbf-4118-a41a-07bea34d32c8} - {c0724499-ab69-40c3-90e2-65242dbd2eaa} @@ -204,6 +228,27 @@ {da8084c0-491b-4eb0-b750-97182a9deed4} + + {56ef157f-ad92-4da7-8fbf-00723f769732} + + + {565f012b-42b7-42c9-81b7-9e93aa378000} + + + {7eead15d-f9dc-4b4d-a653-57d9c090e697} + + + {233e3c4d-e398-4c11-a42c-3483107eb8e9} + + + {8d80e304-a42d-411a-9528-811eddff3191} + + + {eabf472c-e198-409a-a65b-7c087ae911d0} + + + {1fff3bd8-44ae-41df-8dd4-8bb6f07b2908} + @@ -284,24 +329,12 @@ beast_core\maths - - beast_core\maths - beast_core\maths beast_core\maths - - beast_core\memory - - - beast_core\memory - - - beast_core\memory - beast_core\memory @@ -350,9 +383,6 @@ beast_core\network - - beast_core\network - beast_core\streams @@ -377,33 +407,12 @@ beast_core\streams - - beast_core\text - - - beast_core\text - - - beast_core\text - - - beast_core\text - - - beast_core\text - beast_core\text beast_core\text - - beast_core\text - - - beast_core\text - beast_core\text @@ -678,9 +687,6 @@ beast_core\maths - - beast_core\memory - beast_core\memory @@ -786,18 +792,9 @@ beast_core\system - - beast_core\system - beast_core\system - - beast_core\system - - - beast_core\system - beast_core\system @@ -813,12 +810,6 @@ beast_core\containers - - beast_core\text - - - beast_core\text - beast\intrusive @@ -849,12 +840,6 @@ beast_core\memory - - beast_core\diagnostic - - - beast_asio\parsehttp - beast_asio\async @@ -972,9 +957,6 @@ beast_asio\http - - beast_asio\http - beast\mpl @@ -1047,9 +1029,6 @@ beast\utility - - beast - beast\utility @@ -1104,6 +1083,84 @@ beast_core\thread + + beast\http\impl\http-parser + + + beast + + + beast\strings + + + beast\strings + + + beast\strings + + + beast\strings + + + beast\strings + + + beast\strings + + + beast\strings + + + beast\strings + + + beast\strings + + + beast + + + beast\config + + + beast\config + + + beast\config + + + beast + + + beast\config + + + beast\config + + + beast + + + beast + + + beast + + + beast + + + beast + + + beast_core\system + + + beast\http + + + beast\http + @@ -1223,9 +1280,6 @@ beast_core\network - - beast_core\network - beast_core\streams @@ -1247,18 +1301,12 @@ beast_core\streams - - beast_core\text - beast_core\text beast_core\text - - beast_core\text - beast_core\text @@ -1508,9 +1556,6 @@ beast_core\containers - - beast_asio\parsehttp - beast_asio\async @@ -1580,9 +1625,6 @@ beast_asio\http - - beast_asio\http - beast_crypto @@ -1637,6 +1679,39 @@ beast_core\thread + + beast\http\impl\http-parser + + + beast\http\impl\http-parser + + + beast\http\impl\http-parser\contrib + + + beast\http\impl\http-parser\contrib + + + beast\http + + + beast\http\impl + + + beast\strings\impl + + + beast\strings\impl + + + beast\strings + + + beast\http\impl + + + beast\http\impl + diff --git a/src/beast/modules/beast_core/maths/MathsFunctions.h b/src/beast/beast/Arithmetic.h similarity index 97% rename from src/beast/modules/beast_core/maths/MathsFunctions.h rename to src/beast/beast/Arithmetic.h index 4ccd4eab5c..15b2852f60 100644 --- a/src/beast/modules/beast_core/maths/MathsFunctions.h +++ b/src/beast/beast/Arithmetic.h @@ -21,10 +21,11 @@ */ //============================================================================== -#ifndef BEAST_MATHSFUNCTIONS_H_INCLUDED -#define BEAST_MATHSFUNCTIONS_H_INCLUDED +#ifndef BEAST_ARITHMETIC_H_INCLUDED +#define BEAST_ARITHMETIC_H_INCLUDED + +namespace beast { -//============================================================================== // Some indispensible min/max functions /** Returns the larger of two values. */ @@ -199,7 +200,7 @@ inline void swapVariables (Type& variable1, Type& variable2) @endcode */ template -inline int numElementsInArray (Type (&array)[N]) +int numElementsInArray (Type (&array)[N]) { (void) array; // (required to avoid a spurious warning in MS compilers) (void) sizeof (0[array]); // This line should cause an error if you pass an object with a user-defined subscript operator @@ -440,7 +441,7 @@ namespace TypeHelpers template <> struct SmallestFloatType { typedef double type; }; } +} -//============================================================================== +#endif -#endif // BEAST_MATHSFUNCTIONS_H_INCLUDED diff --git a/src/beast/beast/Atomic.h b/src/beast/beast/Atomic.h index fa498aadc9..e7204003d1 100644 --- a/src/beast/beast/Atomic.h +++ b/src/beast/beast/Atomic.h @@ -24,6 +24,9 @@ #ifndef BEAST_ATOMIC_H_INCLUDED #define BEAST_ATOMIC_H_INCLUDED +#include "Config.h" +#include "StaticAssert.h" + namespace beast { //============================================================================== diff --git a/src/beast/modules/beast_core/memory/ByteOrder.h b/src/beast/beast/ByteOrder.h similarity index 79% rename from src/beast/modules/beast_core/memory/ByteOrder.h rename to src/beast/beast/ByteOrder.h index 191de0d943..dcc88d43e5 100644 --- a/src/beast/modules/beast_core/memory/ByteOrder.h +++ b/src/beast/beast/ByteOrder.h @@ -24,6 +24,10 @@ #ifndef BEAST_BYTEORDER_H_INCLUDED #define BEAST_BYTEORDER_H_INCLUDED +#include "Uncopyable.h" + +namespace beast { + //============================================================================== /** Contains static methods for converting the byte order between different endiannesses. @@ -182,5 +186,109 @@ inline int ByteOrder::bigEndian24Bit (const char* const bytes) inline void ByteOrder::littleEndian24BitToChars (const int value, char* const destBytes) { destBytes[0] = (char)(value & 0xff); destBytes[1] = (char)((value >> 8) & 0xff); destBytes[2] = (char)((value >> 16) & 0xff); } inline void ByteOrder::bigEndian24BitToChars (const int value, char* const destBytes) { destBytes[0] = (char)((value >> 16) & 0xff); destBytes[1] = (char)((value >> 8) & 0xff); destBytes[2] = (char)(value & 0xff); } -#endif +namespace detail +{ +/** Specialized helper class template for swapping bytes. + + Normally you won't use this directly, use the helper function + byteSwap instead. You can specialize this class for your + own user defined types, as was done for uint24. + + @see swapBytes, uint24 +*/ +template +struct SwapBytes +{ + inline IntegralType operator() (IntegralType value) const noexcept + { + return ByteOrder::swap (value); + } +}; + +// Specializations for signed integers + +template <> +struct SwapBytes +{ + inline int16 operator() (int16 value) const noexcept + { + return static_cast (ByteOrder::swap (static_cast (value))); + } +}; + +template <> +struct SwapBytes +{ + inline int32 operator() (int32 value) const noexcept + { + return static_cast (ByteOrder::swap (static_cast (value))); + } +}; + +template <> +struct SwapBytes +{ + inline int64 operator() (int64 value) const noexcept + { + return static_cast (ByteOrder::swap (static_cast (value))); + } +}; + +} + +//------------------------------------------------------------------------------ + +/** Returns a type with the bytes swapped. + Little endian becomes big endian and vice versa. The underlying + type must be an integral type or behave like one. +*/ +template +inline IntegralType swapBytes (IntegralType value) noexcept +{ + return detail::SwapBytes () (value); +} + +/** Returns the machine byte-order value to little-endian byte order. */ +template +inline IntegralType toLittleEndian (IntegralType value) noexcept +{ +#if BEAST_LITTLE_ENDIAN + return value; +#else + return swapBytes (value); +#endif +} + +/** Returns the machine byte-order value to big-endian byte order. */ +template +inline IntegralType toBigEndian (IntegralType value) noexcept +{ +#if BEAST_LITTLE_ENDIAN + return swapBytes (value); +#else + return value; +#endif +} + +/** Returns the machine byte-order value to network byte order. */ +template +inline IntegralType toNetworkByteOrder (IntegralType value) noexcept +{ + return toBigEndian (value); +} + +/** Converts from network byte order to machine byte order. */ +template +inline IntegralType fromNetworkByteOrder (IntegralType value) noexcept +{ +#if BEAST_LITTLE_ENDIAN + return swapBytes (value); +#else + return value; +#endif +} + +} + +#endif diff --git a/src/beast/beast/Config.h b/src/beast/beast/Config.h index d67089d4cd..89353891dd 100644 --- a/src/beast/beast/Config.h +++ b/src/beast/beast/Config.h @@ -26,194 +26,10 @@ // VFALCO NOTE this is analogous to -//============================================================================== -/* This file figures out which platform is being built, and defines some macros - that the rest of the code can use for OS-specific compilation. - - Macros that will be set here are: - - - One of BEAST_WINDOWS, BEAST_MAC BEAST_LINUX, BEAST_IOS, BEAST_ANDROID, etc. - - Either BEAST_32BIT or BEAST_64BIT, depending on the architecture. - - Either BEAST_LITTLE_ENDIAN or BEAST_BIG_ENDIAN. - - Either BEAST_INTEL or BEAST_PPC - - Either BEAST_GCC or BEAST_MSVC -*/ - -//============================================================================== -#if (defined (_WIN32) || defined (_WIN64)) - #define BEAST_WIN32 1 - #define BEAST_WINDOWS 1 -#elif defined (BEAST_ANDROID) - #undef BEAST_ANDROID - #define BEAST_ANDROID 1 -#elif defined (LINUX) || defined (__linux__) - #define BEAST_LINUX 1 -#elif defined (__APPLE_CPP__) || defined(__APPLE_CC__) - #define Point CarbonDummyPointName // (workaround to avoid definition of "Point" by old Carbon headers) - #define Component CarbonDummyCompName - #include // (needed to find out what platform we're using) - #undef Point - #undef Component - - #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR - #define BEAST_IPHONE 1 - #define BEAST_IOS 1 - #else - #define BEAST_MAC 1 - #endif -#elif defined (__FreeBSD__) - #define BEAST_BSD 1 -#else - #error "Unknown platform!" -#endif - -//============================================================================== -#if BEAST_WINDOWS - #ifdef _MSC_VER - #ifdef _WIN64 - #define BEAST_64BIT 1 - #else - #define BEAST_32BIT 1 - #endif - #endif - - #ifdef _DEBUG - #define BEAST_DEBUG 1 - #endif - - #ifdef __MINGW32__ - #define BEAST_MINGW 1 - #ifdef __MINGW64__ - #define BEAST_64BIT 1 - #else - #define BEAST_32BIT 1 - #endif - #endif - - /** If defined, this indicates that the processor is little-endian. */ - #define BEAST_LITTLE_ENDIAN 1 - - #define BEAST_INTEL 1 -#endif - -//============================================================================== -#if BEAST_MAC || BEAST_IOS - - #if defined (DEBUG) || defined (_DEBUG) || ! (defined (NDEBUG) || defined (_NDEBUG)) - #define BEAST_DEBUG 1 - #endif - - #if ! (defined (DEBUG) || defined (_DEBUG) || defined (NDEBUG) || defined (_NDEBUG)) - #warning "Neither NDEBUG or DEBUG has been defined - you should set one of these to make it clear whether this is a release build," - #endif - - #ifdef __LITTLE_ENDIAN__ - #define BEAST_LITTLE_ENDIAN 1 - #else - #define BEAST_BIG_ENDIAN 1 - #endif -#endif - -#if BEAST_MAC - - #if defined (__ppc__) || defined (__ppc64__) - #define BEAST_PPC 1 - #elif defined (__arm__) - #define BEAST_ARM 1 - #else - #define BEAST_INTEL 1 - #endif - - #ifdef __LP64__ - #define BEAST_64BIT 1 - #else - #define BEAST_32BIT 1 - #endif - - #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_4 - #error "Building for OSX 10.3 is no longer supported!" - #endif - - #ifndef MAC_OS_X_VERSION_10_5 - #error "To build with 10.4 compatibility, use a 10.5 or 10.6 SDK and set the deployment target to 10.4" - #endif +#include "Version.h" +#include "config/PlatformConfig.h" +#include "config/CompilerConfig.h" +#include "config/StandardConfig.h" +#include "config/ConfigCheck.h" #endif - -//============================================================================== -#if BEAST_LINUX || BEAST_ANDROID || BEAST_BSD - - #ifdef _DEBUG - #define BEAST_DEBUG 1 - #endif - - // Allow override for big-endian Linux platforms - #if defined (__LITTLE_ENDIAN__) || ! defined (BEAST_BIG_ENDIAN) - #define BEAST_LITTLE_ENDIAN 1 - #undef BEAST_BIG_ENDIAN - #else - #undef BEAST_LITTLE_ENDIAN - #define BEAST_BIG_ENDIAN 1 - #endif - - #if defined (__LP64__) || defined (_LP64) - #define BEAST_64BIT 1 - #else - #define BEAST_32BIT 1 - #endif - - #if __MMX__ || __SSE__ || __amd64__ - #ifdef __arm__ - #define BEAST_ARM 1 - #else - #define BEAST_INTEL 1 - #endif - #endif -#endif - -//============================================================================== -// Compiler type macros. - -#ifdef __clang__ - #define BEAST_CLANG 1 - #define BEAST_GCC 1 -#elif defined (__GNUC__) - #define BEAST_GCC 1 -#elif defined (_MSC_VER) - #define BEAST_MSVC 1 - - #if _MSC_VER < 1500 - #define BEAST_VC8_OR_EARLIER 1 - - #if _MSC_VER < 1400 - #define BEAST_VC7_OR_EARLIER 1 - - #if _MSC_VER < 1300 - #warning "MSVC 6.0 is no longer supported!" - #endif - #endif - #endif - - #if BEAST_64BIT || ! BEAST_VC7_OR_EARLIER - #define BEAST_USE_INTRINSICS 1 - #endif -#else - #error unknown compiler -#endif - -//------------------------------------------------------------------------------ - -// Handy macro that lets pragma warnings be clicked in the output window -// -// Usage: #pragma message(BEAST_FILEANDLINE_ "Advertise here!") -// -// Note that a space following the macro is mandatory for C++11. -// -// This is here so it can be used in C compilations that include this directly. -// -#define BEAST_PP_STR2_(x) #x -#define BEAST_PP_STR1_(x) BEAST_PP_STR2_(x) -#define BEAST_FILEANDLINE_ __FILE__ "(" BEAST_PP_STR1_(__LINE__) "): warning:" - -#endif - diff --git a/src/beast/beast/HTTP.h b/src/beast/beast/HTTP.h new file mode 100644 index 0000000000..400191ed25 --- /dev/null +++ b/src/beast/beast/HTTP.h @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_HTTP_H_INCLUDED +#define BEAST_HTTP_H_INCLUDED + +#include "http/URL.h" +#include "http/ParsedURL.h" + +#endif diff --git a/src/beast/modules/beast_core/memory/HeapBlock.h b/src/beast/beast/HeapBlock.h similarity index 89% rename from src/beast/modules/beast_core/memory/HeapBlock.h rename to src/beast/beast/HeapBlock.h index 8d4dfc92f8..144edae140 100644 --- a/src/beast/modules/beast_core/memory/HeapBlock.h +++ b/src/beast/beast/HeapBlock.h @@ -24,6 +24,42 @@ #ifndef BEAST_HEAPBLOCK_H_INCLUDED #define BEAST_HEAPBLOCK_H_INCLUDED +#include "Memory.h" +#include "Uncopyable.h" + +// If the MSVC debug heap headers were included, disable +// the macros during the juce include since they conflict. +#ifdef _CRTDBG_MAP_ALLOC +#pragma push_macro("calloc") +#pragma push_macro("free") +#pragma push_macro("malloc") +#pragma push_macro("realloc") +#pragma push_macro("_recalloc") +#pragma push_macro("_aligned_free") +#pragma push_macro("_aligned_malloc") +#pragma push_macro("_aligned_offset_malloc") +#pragma push_macro("_aligned_realloc") +#pragma push_macro("_aligned_recalloc") +#pragma push_macro("_aligned_offset_realloc") +#pragma push_macro("_aligned_offset_recalloc") +#pragma push_macro("_aligned_msize") +#undef calloc +#undef free +#undef malloc +#undef realloc +#undef _recalloc +#undef _aligned_free +#undef _aligned_malloc +#undef _aligned_offset_malloc +#undef _aligned_realloc +#undef _aligned_recalloc +#undef _aligned_offset_realloc +#undef _aligned_offset_recalloc +#undef _aligned_msize +#endif + +namespace beast { + #ifndef DOXYGEN namespace HeapBlockHelper { @@ -305,5 +341,23 @@ private: #endif }; +} + +#ifdef _CRTDBG_MAP_ALLOC +#pragma pop_macro("_aligned_msize") +#pragma pop_macro("_aligned_offset_recalloc") +#pragma pop_macro("_aligned_offset_realloc") +#pragma pop_macro("_aligned_recalloc") +#pragma pop_macro("_aligned_realloc") +#pragma pop_macro("_aligned_offset_malloc") +#pragma pop_macro("_aligned_malloc") +#pragma pop_macro("_aligned_free") +#pragma pop_macro("_recalloc") +#pragma pop_macro("realloc") +#pragma pop_macro("malloc") +#pragma pop_macro("free") +#pragma pop_macro("calloc") +#endif + +#endif -#endif // BEAST_HEAPBLOCK_H_INCLUDED diff --git a/src/beast/modules/beast_core/memory/Memory.h b/src/beast/beast/Memory.h similarity index 99% rename from src/beast/modules/beast_core/memory/Memory.h rename to src/beast/beast/Memory.h index b67ec0cd7a..f39fa9ca13 100644 --- a/src/beast/modules/beast_core/memory/Memory.h +++ b/src/beast/beast/Memory.h @@ -24,6 +24,8 @@ #ifndef BEAST_MEMORY_H_INCLUDED #define BEAST_MEMORY_H_INCLUDED +namespace beast { + //============================================================================== /** Fills a block of memory with zeros. */ inline void zeromem (void* memory, size_t numBytes) noexcept { memset (memory, 0, numBytes); } @@ -90,5 +92,7 @@ inline Type* createCopyIfNotNull (const Type* pointer) { return pointer != n #define BEAST_AUTORELEASEPOOL #endif +} + #endif diff --git a/src/beast/beast/Strings.h b/src/beast/beast/Strings.h new file mode 100644 index 0000000000..5b76162400 --- /dev/null +++ b/src/beast/beast/Strings.h @@ -0,0 +1,27 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_STRINGS_H_INCLUDED +#define BEAST_STRINGS_H_INCLUDED + +#include "strings/String.h" +#include "strings/NewLine.h" + +#endif + diff --git a/src/beast/beast/Version.h b/src/beast/beast/Version.h new file mode 100644 index 0000000000..e409692fb6 --- /dev/null +++ b/src/beast/beast/Version.h @@ -0,0 +1,40 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_VERSION_H_INCLUDED +#define BEAST_VERSION_H_INCLUDED + +/** Current BEAST version number. + See also SystemStats::getBeastVersion() for a string version. +*/ +// VFALCO TODO Replace this with SemanticVerson +#define BEAST_MAJOR_VERSION 1 +#define BEAST_MINOR_VERSION 0 +#define BEAST_BUILDNUMBER 0 + +/** Current Beast version number. + Bits 16 to 32 = major version. + Bits 8 to 16 = minor version. + Bits 0 to 8 = point release. + See also SystemStats::getBeastVersion() for a string version. +*/ +#define BEAST_VERSION ((BEAST_MAJOR_VERSION << 16) + (BEAST_MINOR_VERSION << 8) + BEAST_BUILDNUMBER) + +#endif + diff --git a/src/beast/modules/beast_core/system/PlatformDefs.h b/src/beast/beast/config/CompilerConfig.h similarity index 92% rename from src/beast/modules/beast_core/system/PlatformDefs.h rename to src/beast/beast/config/CompilerConfig.h index 5039445a5c..46e3afbfa5 100644 --- a/src/beast/modules/beast_core/system/PlatformDefs.h +++ b/src/beast/beast/config/CompilerConfig.h @@ -21,8 +21,14 @@ */ //============================================================================== -#ifndef BEAST_CORE_PLATFORMDEFS_H_INCLUDED -#define BEAST_CORE_PLATFORMDEFS_H_INCLUDED +#ifndef BEAST_CONFIG_COMPILERCONFIG_H_INCLUDED +#define BEAST_CONFIG_COMPILERCONFIG_H_INCLUDED + +// This file has to work when included in a C source file. + +#ifndef BEAST_CONFIG_PLATFORMCONFIG_H_INCLUDED +#error "PlatformConfig.h must come first!" +#endif // This file defines miscellaneous macros for debugging, assertions, etc. @@ -84,6 +90,17 @@ //------------------------------------------------------------------------------ +#ifdef __cplusplus +extern "C" { +#endif +/** Report a fatal error message and terminate the application. + Normally you won't call this directly. +*/ +extern void beast_reportFatalError (char const* message, char const* fileName, int lineNumber); +#ifdef __cplusplus +} +#endif + #if BEAST_DEBUG || DOXYGEN /** Writes a string to the standard error stream. @@ -99,17 +116,12 @@ #define bassertfalse { beast_LogCurrentAssertion; if (beast::beast_isRunningUnderDebugger()) beast_breakDebugger; BEAST_ANALYZER_NORETURN } /** Platform-independent assertion macro. - This macro gets turned into a no-op when you're building with debugging turned off, so be careful that the expression you pass to it doesn't perform any actions that are vital for the correct behaviour of your program! @see bassertfalse */ -#if 0 -#define bassert(expression) { if (! (expression)) bassertfalse; } -#else -#define bassert(expression) { if (! (expression)) fatal_error(#expression); } -#endif +#define bassert(expression) { if (! (expression)) beast_reportFatalError(#expression,__FILE__,__LINE__); } #else @@ -283,4 +295,11 @@ #define override #endif +#ifdef __cplusplus +namespace beast { +bool beast_isRunningUnderDebugger(); +void logAssertion (char const* file, int line) noexcept; +} +#endif + #endif diff --git a/src/beast/modules/beast_core/system/BeastConfigCheck.h b/src/beast/beast/config/ConfigCheck.h similarity index 97% rename from src/beast/modules/beast_core/system/BeastConfigCheck.h rename to src/beast/beast/config/ConfigCheck.h index 53a3b433cc..3fd5a17a22 100644 --- a/src/beast/modules/beast_core/system/BeastConfigCheck.h +++ b/src/beast/beast/config/ConfigCheck.h @@ -17,8 +17,8 @@ */ //============================================================================== -#ifndef BEAST_CORE_BEASTCONFIGCHECK_H_INCLUDED -#define BEAST_CORE_BEASTCONFIGCHECK_H_INCLUDED +#ifndef BEAST_CONFIG_CONFIGCHECK_H_INCLUDED +#define BEAST_CONFIG_CONFIGCHECK_H_INCLUDED // This file makes sure that BeastConfig.h was included. // It also sets defaults for all config options. diff --git a/src/beast/modules/beast_core/diagnostic/ContractChecks.h b/src/beast/beast/config/ContractChecks.h similarity index 92% rename from src/beast/modules/beast_core/diagnostic/ContractChecks.h rename to src/beast/beast/config/ContractChecks.h index b7d9e09a0f..59cad4231c 100644 --- a/src/beast/modules/beast_core/diagnostic/ContractChecks.h +++ b/src/beast/beast/config/ContractChecks.h @@ -17,8 +17,10 @@ */ //============================================================================== -#ifndef BEAST_CONTRACTCHECKS_H_INCLUDED -#define BEAST_CONTRACTCHECKS_H_INCLUDED +#ifndef BEAST_CONFIG_CONTRACTCHECKS_H_INCLUDED +#define BEAST_CONFIG_CONTRACTCHECKS_H_INCLUDED + +// This file has to work when included in a C source file. #if defined (fatal_error) || \ defined (fatal_condition) || \ @@ -33,15 +35,13 @@ #error "Programming by contract macros cannot be overriden!" #endif -extern void reportFatalError (char const* message, char const* fileName, int lineNumber); - /** Report a fatal error message and terminate the application. This macro automatically fills in the file and line number Meets this declaration syntax: @code inline void fatal_error (char const* message); @endif @see FatalError */ -#define fatal_error(message) reportFatalError (message, __FILE__, __LINE__) +#define fatal_error(message) beast_reportFatalError (message, __FILE__, __LINE__) /** Reports a fatal error message type if the condition is false The condition is always evaluated regardless of settings. @@ -49,7 +49,7 @@ extern void reportFatalError (char const* message, char const* fileName, int lin @code inline void fatal_condition (bool condition, char const* category); @endcode */ #define fatal_condition(condition,category) static_cast \ - (((!!(condition)) || (reportFatalError ( \ + (((!!(condition)) || (beast_reportFatalError ( \ category " '" BEAST_STRINGIFY(condition) "' failed.", __FILE__, __LINE__), 0))) /** Replacement for assert which generates a fatal error if the condition is false. @@ -65,7 +65,7 @@ extern void reportFatalError (char const* message, char const* fileName, int lin @code inline void fatal_condition (bool condition, char const* category); @endcode */ #define meets_condition(condition,category) static_cast \ - (((!!(condition)) || (reportFatalError ( \ + (((!!(condition)) || (beast_reportFatalError ( \ category " '" BEAST_STRINGIFY(condition) "' failed.", __FILE__, __LINE__), false))) /** Condition tests for programming by contract. diff --git a/src/beast/beast/config/PlatformConfig.h b/src/beast/beast/config/PlatformConfig.h new file mode 100644 index 0000000000..ec59dab8d7 --- /dev/null +++ b/src/beast/beast/config/PlatformConfig.h @@ -0,0 +1,217 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Portions of this file are from JUCE. + Copyright (c) 2013 - Raw Material Software Ltd. + Please visit http://www.juce.com + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_CONFIG_PLATFORMCONFIG_H_INCLUDED +#define BEAST_CONFIG_PLATFORMCONFIG_H_INCLUDED + +//============================================================================== +/* This file figures out which platform is being built, and defines some macros + that the rest of the code can use for OS-specific compilation. + + Macros that will be set here are: + + - One of BEAST_WINDOWS, BEAST_MAC BEAST_LINUX, BEAST_IOS, BEAST_ANDROID, etc. + - Either BEAST_32BIT or BEAST_64BIT, depending on the architecture. + - Either BEAST_LITTLE_ENDIAN or BEAST_BIG_ENDIAN. + - Either BEAST_INTEL or BEAST_PPC + - Either BEAST_GCC or BEAST_MSVC +*/ + +//============================================================================== +#if (defined (_WIN32) || defined (_WIN64)) + #define BEAST_WIN32 1 + #define BEAST_WINDOWS 1 +#elif defined (BEAST_ANDROID) + #undef BEAST_ANDROID + #define BEAST_ANDROID 1 +#elif defined (LINUX) || defined (__linux__) + #define BEAST_LINUX 1 +#elif defined (__APPLE_CPP__) || defined(__APPLE_CC__) + #define Point CarbonDummyPointName // (workaround to avoid definition of "Point" by old Carbon headers) + #define Component CarbonDummyCompName + #include // (needed to find out what platform we're using) + #undef Point + #undef Component + + #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR + #define BEAST_IPHONE 1 + #define BEAST_IOS 1 + #else + #define BEAST_MAC 1 + #endif +#elif defined (__FreeBSD__) + #define BEAST_BSD 1 +#else + #error "Unknown platform!" +#endif + +//============================================================================== +#if BEAST_WINDOWS + #ifdef _MSC_VER + #ifdef _WIN64 + #define BEAST_64BIT 1 + #else + #define BEAST_32BIT 1 + #endif + #endif + + #ifdef _DEBUG + #define BEAST_DEBUG 1 + #endif + + #ifdef __MINGW32__ + #define BEAST_MINGW 1 + #ifdef __MINGW64__ + #define BEAST_64BIT 1 + #else + #define BEAST_32BIT 1 + #endif + #endif + + /** If defined, this indicates that the processor is little-endian. */ + #define BEAST_LITTLE_ENDIAN 1 + + #define BEAST_INTEL 1 +#endif + +//============================================================================== +#if BEAST_MAC || BEAST_IOS + + #if defined (DEBUG) || defined (_DEBUG) || ! (defined (NDEBUG) || defined (_NDEBUG)) + #define BEAST_DEBUG 1 + #endif + + #if ! (defined (DEBUG) || defined (_DEBUG) || defined (NDEBUG) || defined (_NDEBUG)) + #warning "Neither NDEBUG or DEBUG has been defined - you should set one of these to make it clear whether this is a release build," + #endif + + #ifdef __LITTLE_ENDIAN__ + #define BEAST_LITTLE_ENDIAN 1 + #else + #define BEAST_BIG_ENDIAN 1 + #endif +#endif + +#if BEAST_MAC + + #if defined (__ppc__) || defined (__ppc64__) + #define BEAST_PPC 1 + #elif defined (__arm__) + #define BEAST_ARM 1 + #else + #define BEAST_INTEL 1 + #endif + + #ifdef __LP64__ + #define BEAST_64BIT 1 + #else + #define BEAST_32BIT 1 + #endif + + #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_4 + #error "Building for OSX 10.3 is no longer supported!" + #endif + + #ifndef MAC_OS_X_VERSION_10_5 + #error "To build with 10.4 compatibility, use a 10.5 or 10.6 SDK and set the deployment target to 10.4" + #endif + +#endif + +//============================================================================== +#if BEAST_LINUX || BEAST_ANDROID || BEAST_BSD + + #ifdef _DEBUG + #define BEAST_DEBUG 1 + #endif + + // Allow override for big-endian Linux platforms + #if defined (__LITTLE_ENDIAN__) || ! defined (BEAST_BIG_ENDIAN) + #define BEAST_LITTLE_ENDIAN 1 + #undef BEAST_BIG_ENDIAN + #else + #undef BEAST_LITTLE_ENDIAN + #define BEAST_BIG_ENDIAN 1 + #endif + + #if defined (__LP64__) || defined (_LP64) + #define BEAST_64BIT 1 + #else + #define BEAST_32BIT 1 + #endif + + #if __MMX__ || __SSE__ || __amd64__ + #ifdef __arm__ + #define BEAST_ARM 1 + #else + #define BEAST_INTEL 1 + #endif + #endif +#endif + +//============================================================================== +// Compiler type macros. + +#ifdef __clang__ + #define BEAST_CLANG 1 + #define BEAST_GCC 1 +#elif defined (__GNUC__) + #define BEAST_GCC 1 +#elif defined (_MSC_VER) + #define BEAST_MSVC 1 + + #if _MSC_VER < 1500 + #define BEAST_VC8_OR_EARLIER 1 + + #if _MSC_VER < 1400 + #define BEAST_VC7_OR_EARLIER 1 + + #if _MSC_VER < 1300 + #warning "MSVC 6.0 is no longer supported!" + #endif + #endif + #endif + + #if BEAST_64BIT || ! BEAST_VC7_OR_EARLIER + #define BEAST_USE_INTRINSICS 1 + #endif +#else + #error unknown compiler +#endif + +//------------------------------------------------------------------------------ + +// Handy macro that lets pragma warnings be clicked in the output window +// +// Usage: #pragma message(BEAST_FILEANDLINE_ "Advertise here!") +// +// Note that a space following the macro is mandatory for C++11. +// +// This is here so it can be used in C compilations that include this directly. +// +#define BEAST_PP_STR2_(x) #x +#define BEAST_PP_STR1_(x) BEAST_PP_STR2_(x) +#define BEAST_FILEANDLINE_ __FILE__ "(" BEAST_PP_STR1_(__LINE__) "): warning:" + +#endif + diff --git a/src/beast/modules/beast_core/system/StandardHeader.h b/src/beast/beast/config/StandardConfig.h similarity index 65% rename from src/beast/modules/beast_core/system/StandardHeader.h rename to src/beast/beast/config/StandardConfig.h index 4172ed1c2d..6f2a67c875 100644 --- a/src/beast/modules/beast_core/system/StandardHeader.h +++ b/src/beast/beast/config/StandardConfig.h @@ -21,34 +21,11 @@ */ //============================================================================== -#ifndef BEAST_STANDARDHEADER_H_INCLUDED -#define BEAST_STANDARDHEADER_H_INCLUDED +#ifndef BEAST_CONFIG_STANDARDCONFIG_H_INCLUDED +#define BEAST_CONFIG_STANDARDCONFIG_H_INCLUDED -//------------------------------------------------------------------------------ - -/** Current BEAST version number. - - See also SystemStats::getBeastVersion() for a string version. -*/ -// VFALCO TODO Replace this with SemanticVerson -#define BEAST_MAJOR_VERSION 1 -#define BEAST_MINOR_VERSION 0 -#define BEAST_BUILDNUMBER 0 - -/** Current Beast version number. - - Bits 16 to 32 = major version. - Bits 8 to 16 = minor version. - Bits 0 to 8 = point release. - - See also SystemStats::getBeastVersion() for a string version. -*/ -#define BEAST_VERSION ((BEAST_MAJOR_VERSION << 16) + (BEAST_MINOR_VERSION << 8) + BEAST_BUILDNUMBER) - -//------------------------------------------------------------------------------ - -#ifndef BEAST_CORE_PLATFORMDEFS_H_INCLUDED -#error "PlatformDefs.h must be included first" +#ifndef BEAST_CONFIG_COMPILERCONFIG_H_INCLUDED +#error "CompilerConfig.h must be included first" #endif // Now we'll include some common OS headers.. @@ -57,45 +34,6 @@ #pragma warning (disable: 4514 4245 4100) #endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #if BEAST_USE_INTRINSICS # include #endif diff --git a/src/beast/beast/http/HTTP.cpp b/src/beast/beast/http/HTTP.cpp new file mode 100644 index 0000000000..a4913b0381 --- /dev/null +++ b/src/beast/beast/http/HTTP.cpp @@ -0,0 +1,24 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "BeastConfig.h" + +#include "impl/URL.cpp" +#include "impl/ParsedURL.cpp" +#include "impl/http_parser.cpp" diff --git a/src/beast/beast/http/ParsedURL.h b/src/beast/beast/http/ParsedURL.h new file mode 100644 index 0000000000..69ca4a0746 --- /dev/null +++ b/src/beast/beast/http/ParsedURL.h @@ -0,0 +1,51 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_HTTP_PARSEDURL_H_INCLUDED +#define BEAST_HTTP_PARSEDURL_H_INCLUDED + +#include "../Strings.h" +#include "URL.h" + +namespace beast { + +/** Parses a String containing a URL. */ +class ParsedURL +{ +public: + ParsedURL (); + explicit ParsedURL (String const& url); + ParsedURL (int error, URL const& url); + ParsedURL (ParsedURL const& other); + ParsedURL& operator= (ParsedURL const& other); + + /** Zero for success, else a non zero value indicating failure. */ + int error () const; + + /** The parsed URL if there was no error. */ + URL url () const; + +private: + int m_error; + URL m_url; +}; + +} + +#endif diff --git a/src/beast/modules/beast_asio/http/UniformResourceLocator.h b/src/beast/beast/http/URL.h similarity index 74% rename from src/beast/modules/beast_asio/http/UniformResourceLocator.h rename to src/beast/beast/http/URL.h index 54c2b3ebc7..5d80bd809c 100644 --- a/src/beast/modules/beast_asio/http/UniformResourceLocator.h +++ b/src/beast/beast/http/URL.h @@ -17,20 +17,24 @@ */ //============================================================================== -#ifndef BEAST_ASIO_PROTOCOL_UNIFORMRESOURCELOCATOR_H_INCLUDED -#define BEAST_ASIO_PROTOCOL_UNIFORMRESOURCELOCATOR_H_INCLUDED +#ifndef BEAST_HTTP_URL_H_INCLUDED +#define BEAST_HTTP_URL_H_INCLUDED + +#include "../strings/String.h" + +namespace beast { /** A URL. The accompanying robust parser is hardened against all forms of attack. */ -class UniformResourceLocator +class URL { public: /** Construct an empty URL. */ - explicit UniformResourceLocator (); + explicit URL (); /** Construct a URL from it's components. */ - UniformResourceLocator ( + URL ( String schema_, String host_, uint16 port_, @@ -41,10 +45,10 @@ public: String userinfo_ = ""); /** Copy construct a URL. */ - UniformResourceLocator (UniformResourceLocator const& other); + URL (URL const& other); /** Copy assign a URL. */ - UniformResourceLocator& operator= (UniformResourceLocator const& other); + URL& operator= (URL const& other); /** Returns `true` if this is an empty URL. */ bool empty () const; @@ -99,28 +103,6 @@ private: String m_userinfo; }; -//------------------------------------------------------------------------------ - -/** Parses a String containing a URL. -*/ -class ParsedURL -{ -public: - ParsedURL (); - explicit ParsedURL (String const& url); - ParsedURL (int error, UniformResourceLocator const& url); - ParsedURL (ParsedURL const& other); - ParsedURL& operator= (ParsedURL const& other); - - /** Zero for success, else a non zero value indicating failure. */ - int error () const; - - /** The parsed URL if there was no error. */ - UniformResourceLocator url () const; - -private: - int m_error; - UniformResourceLocator m_url; -}; +} #endif diff --git a/src/beast/modules/beast_asio/http/UniformResourceLocator.cpp b/src/beast/beast/http/impl/ParsedURL.cpp similarity index 59% rename from src/beast/modules/beast_asio/http/UniformResourceLocator.cpp rename to src/beast/beast/http/impl/ParsedURL.cpp index d1e76d5b4e..b76f1df676 100644 --- a/src/beast/modules/beast_asio/http/UniformResourceLocator.cpp +++ b/src/beast/beast/http/impl/ParsedURL.cpp @@ -17,139 +17,13 @@ */ //============================================================================== -UniformResourceLocator::UniformResourceLocator () - : m_port (0) -{ -} +#include "../ParsedURL.h" -UniformResourceLocator::UniformResourceLocator ( - String scheme_, - String host_, - uint16 port_, - String port_string_, - String path_, - String query_, - String fragment_, - String userinfo_) - : m_scheme (scheme_) - , m_host (host_) - , m_port (port_) - , m_port_string (port_string_) - , m_path (path_) - , m_query (query_) - , m_fragment (fragment_) - , m_userinfo (userinfo_) -{ -} +#include "http-parser/http_parser.h" -UniformResourceLocator::UniformResourceLocator (UniformResourceLocator const& other) - : m_scheme (other.m_scheme) - , m_host (other.m_host) - , m_port (other.m_port) - , m_port_string (other.m_port_string) - , m_path (other.m_path) - , m_query (other.m_query) - , m_fragment (other.m_fragment) - , m_userinfo (other.m_userinfo) -{ -} +#include "../../../modules/beast_core/beast_core.h" // for UnitTest -UniformResourceLocator& UniformResourceLocator::operator= (UniformResourceLocator const& other) -{ - m_scheme = other.m_scheme; - m_host = other.m_host; - m_port = other.m_port; - m_port_string = other.m_port_string; - m_path = other.m_path; - m_query = other.m_query; - m_fragment = other.m_fragment; - m_userinfo = other.m_userinfo; - return *this; -} - -//------------------------------------------------------------------------------ - -bool UniformResourceLocator::empty () const -{ - return m_scheme == String::empty; -} - -String UniformResourceLocator::scheme () const -{ - return m_scheme; -} - -String UniformResourceLocator::host () const -{ - return m_host; -} - -String UniformResourceLocator::port_string () const -{ - return m_port_string; -} - -uint16 UniformResourceLocator::port () const -{ - return m_port; -} - -String UniformResourceLocator::path () const -{ - return m_path; -} - -String UniformResourceLocator::query () const -{ - return m_query; -} - -String UniformResourceLocator::fragment () const -{ - return m_fragment; -} - -String UniformResourceLocator::userinfo () const -{ - return m_userinfo; -} - -//------------------------------------------------------------------------------ -/* - From - http://en.wikipedia.org/wiki/URI_scheme - - : [ ? ] [ # ] - - e.g. - - foo://username:password@example.com:8042/over/there/index.dtb?type=animal&name=narwhal#nose -*/ -String UniformResourceLocator::full () const -{ - String s; - - s = scheme () + "://"; - - if (userinfo () != String::empty) - s = userinfo () + "@"; - - s = s + host (); - - if (port () != 0) - s = s + ":" + String::fromNumber (port ()); - - s = s + path (); - - if (query () != String::empty) - s = "?" + query (); - - if (fragment () != String::empty) - s = "#" + fragment (); - - return s; -} -//------------------------------------------------------------------------------ +namespace beast { ParsedURL::ParsedURL () : m_error (0) @@ -231,7 +105,7 @@ ParsedURL::ParsedURL (String const& url) u.field_data [UF_USERINFO].len); } - m_url = UniformResourceLocator ( + m_url = URL ( scheme_, host_, port_, @@ -243,7 +117,7 @@ ParsedURL::ParsedURL (String const& url) } } -ParsedURL::ParsedURL (int error, UniformResourceLocator const& url) +ParsedURL::ParsedURL (int error, URL const& url) : m_error (error) , m_url (url) { @@ -267,7 +141,7 @@ int ParsedURL::error () const return m_error; } -UniformResourceLocator ParsedURL::url () const +URL ParsedURL::url () const { return m_url; } @@ -302,3 +176,5 @@ public: }; static ParsedURLTests parsedURLTests; + +} diff --git a/src/beast/beast/http/impl/README.md b/src/beast/beast/http/impl/README.md new file mode 100644 index 0000000000..ab82bbba99 --- /dev/null +++ b/src/beast/beast/http/impl/README.md @@ -0,0 +1,3 @@ +git-subtree: "http-parser" +remote: https://github.com/joyent/http-parser.git +branch: master diff --git a/src/beast/beast/http/impl/URL.cpp b/src/beast/beast/http/impl/URL.cpp new file mode 100644 index 0000000000..d0ddfe74a0 --- /dev/null +++ b/src/beast/beast/http/impl/URL.cpp @@ -0,0 +1,158 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "../URL.h" + +namespace beast { + +URL::URL () + : m_port (0) +{ +} + +URL::URL ( + String scheme_, + String host_, + uint16 port_, + String port_string_, + String path_, + String query_, + String fragment_, + String userinfo_) + : m_scheme (scheme_) + , m_host (host_) + , m_port (port_) + , m_port_string (port_string_) + , m_path (path_) + , m_query (query_) + , m_fragment (fragment_) + , m_userinfo (userinfo_) +{ +} + +URL::URL (URL const& other) + : m_scheme (other.m_scheme) + , m_host (other.m_host) + , m_port (other.m_port) + , m_port_string (other.m_port_string) + , m_path (other.m_path) + , m_query (other.m_query) + , m_fragment (other.m_fragment) + , m_userinfo (other.m_userinfo) +{ +} + +URL& URL::operator= (URL const& other) +{ + m_scheme = other.m_scheme; + m_host = other.m_host; + m_port = other.m_port; + m_port_string = other.m_port_string; + m_path = other.m_path; + m_query = other.m_query; + m_fragment = other.m_fragment; + m_userinfo = other.m_userinfo; + return *this; +} + +//------------------------------------------------------------------------------ + +bool URL::empty () const +{ + return m_scheme == String::empty; +} + +String URL::scheme () const +{ + return m_scheme; +} + +String URL::host () const +{ + return m_host; +} + +String URL::port_string () const +{ + return m_port_string; +} + +uint16 URL::port () const +{ + return m_port; +} + +String URL::path () const +{ + return m_path; +} + +String URL::query () const +{ + return m_query; +} + +String URL::fragment () const +{ + return m_fragment; +} + +String URL::userinfo () const +{ + return m_userinfo; +} + +//------------------------------------------------------------------------------ +/* + From + http://en.wikipedia.org/wiki/URI_scheme + + : [ ? ] [ # ] + + e.g. + + foo://username:password@example.com:8042/over/there/index.dtb?type=animal&name=narwhal#nose +*/ +String URL::full () const +{ + String s; + + s = scheme () + "://"; + + if (userinfo () != String::empty) + s = userinfo () + "@"; + + s = s + host (); + + if (port () != 0) + s = s + ":" + String::fromNumber (port ()); + + s = s + path (); + + if (query () != String::empty) + s = "?" + query (); + + if (fragment () != String::empty) + s = "#" + fragment (); + + return s; +} + +} + diff --git a/src/beast/beast/http/impl/http_parser.cpp b/src/beast/beast/http/impl/http_parser.cpp new file mode 100644 index 0000000000..42b5b8eb24 --- /dev/null +++ b/src/beast/beast/http/impl/http_parser.cpp @@ -0,0 +1,36 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "BeastConfig.h" + +#include "../../Config.h" + +namespace beast { + +#ifdef _MSC_VER +#pragma warning (push) +#pragma warning (disable: 4127) // conditional expression is constant +#pragma warning (disable: 4244) // integer conversion, possible loss of data +#endif +#include "http-parser/http_parser.c" +#ifdef _MSC_VER +#pragma warning (pop) +#endif + +} diff --git a/src/beast/beast/net/IPEndpoint.h b/src/beast/beast/net/IPEndpoint.h index 8135898fbf..3a2fb63b3f 100644 --- a/src/beast/beast/net/IPEndpoint.h +++ b/src/beast/beast/net/IPEndpoint.h @@ -21,9 +21,9 @@ #define BEAST_NET_IPENDPOINT_H_INCLUDED #include -#include -#include - +#include +#include + #include "../CStdInt.h" #include "../mpl/IfCond.h" diff --git a/src/beast/beast/net/Net.cpp b/src/beast/beast/net/Net.cpp index e5718bc033..1c045fd65d 100644 --- a/src/beast/beast/net/Net.cpp +++ b/src/beast/beast/net/Net.cpp @@ -19,8 +19,8 @@ #include "BeastConfig.h" -#include "../../modules/beast_core/beast_core.h" // for UnitTest - #include "../Config.h" +#include "../../modules/beast_core/beast_core.h" // for UnitTest + #include "impl/IPEndpoint.cpp" diff --git a/src/beast/modules/beast_core/text/CharPointer_ASCII.h b/src/beast/beast/strings/CharPointer_ASCII.h similarity index 99% rename from src/beast/modules/beast_core/text/CharPointer_ASCII.h rename to src/beast/beast/strings/CharPointer_ASCII.h index 7fc76609d2..663c61ccaa 100644 --- a/src/beast/modules/beast_core/text/CharPointer_ASCII.h +++ b/src/beast/beast/strings/CharPointer_ASCII.h @@ -24,6 +24,7 @@ #ifndef BEAST_CHARPOINTER_ASCII_H_INCLUDED #define BEAST_CHARPOINTER_ASCII_H_INCLUDED +namespace beast { //============================================================================== /** @@ -378,5 +379,7 @@ private: CharType* data; }; +} + +#endif -#endif // BEAST_CHARPOINTER_ASCII_H_INCLUDED diff --git a/src/beast/modules/beast_core/text/CharPointer_UTF16.h b/src/beast/beast/strings/CharPointer_UTF16.h similarity index 99% rename from src/beast/modules/beast_core/text/CharPointer_UTF16.h rename to src/beast/beast/strings/CharPointer_UTF16.h index 6279e48c61..98558b4ddd 100644 --- a/src/beast/modules/beast_core/text/CharPointer_UTF16.h +++ b/src/beast/beast/strings/CharPointer_UTF16.h @@ -24,6 +24,7 @@ #ifndef BEAST_CHARPOINTER_UTF16_H_INCLUDED #define BEAST_CHARPOINTER_UTF16_H_INCLUDED +namespace beast { //============================================================================== /** @@ -516,4 +517,7 @@ private: } }; -#endif // BEAST_CHARPOINTER_UTF16_H_INCLUDED +} + +#endif + diff --git a/src/beast/modules/beast_core/text/CharPointer_UTF32.h b/src/beast/beast/strings/CharPointer_UTF32.h similarity index 99% rename from src/beast/modules/beast_core/text/CharPointer_UTF32.h rename to src/beast/beast/strings/CharPointer_UTF32.h index 879d9e22cc..847a3001a4 100644 --- a/src/beast/modules/beast_core/text/CharPointer_UTF32.h +++ b/src/beast/beast/strings/CharPointer_UTF32.h @@ -24,6 +24,7 @@ #ifndef BEAST_CHARPOINTER_UTF32_H_INCLUDED #define BEAST_CHARPOINTER_UTF32_H_INCLUDED +namespace beast { //============================================================================== /** @@ -369,5 +370,7 @@ private: CharType* data; }; +} + +#endif -#endif // BEAST_CHARPOINTER_UTF32_H_INCLUDED diff --git a/src/beast/modules/beast_core/text/CharPointer_UTF8.h b/src/beast/beast/strings/CharPointer_UTF8.h similarity index 99% rename from src/beast/modules/beast_core/text/CharPointer_UTF8.h rename to src/beast/beast/strings/CharPointer_UTF8.h index 99ef9a03d9..abf694b9d0 100644 --- a/src/beast/modules/beast_core/text/CharPointer_UTF8.h +++ b/src/beast/beast/strings/CharPointer_UTF8.h @@ -24,6 +24,12 @@ #ifndef BEAST_CHARPOINTER_UTF8_H_INCLUDED #define BEAST_CHARPOINTER_UTF8_H_INCLUDED +#include + +#include "../Atomic.h" + +namespace beast { + //============================================================================== /** Wraps a pointer to a null-terminated UTF-8 character string, and provides @@ -570,5 +576,7 @@ private: CharType* data; }; +} + #endif diff --git a/src/beast/modules/beast_core/text/CharacterFunctions.h b/src/beast/beast/strings/CharacterFunctions.h similarity index 99% rename from src/beast/modules/beast_core/text/CharacterFunctions.h rename to src/beast/beast/strings/CharacterFunctions.h index 2ce3139fca..65d533270e 100644 --- a/src/beast/modules/beast_core/text/CharacterFunctions.h +++ b/src/beast/beast/strings/CharacterFunctions.h @@ -21,9 +21,13 @@ */ //============================================================================== -#ifndef BEAST_CHARACTERFUNCTIONS_H_INCLUDED -#define BEAST_CHARACTERFUNCTIONS_H_INCLUDED +#ifndef BEAST_STRINGS_CHARACTERFUNCTIONS_H_INCLUDED +#define BEAST_STRINGS_CHARACTERFUNCTIONS_H_INCLUDED +#include "../Config.h" +#include "../CStdInt.h" + +namespace beast { //============================================================================== #if BEAST_WINDOWS && ! DOXYGEN @@ -581,5 +585,7 @@ private: static double mulexp10 (const double value, int exponent) noexcept; }; +} + +#endif -#endif // BEAST_CHARACTERFUNCTIONS_H_INCLUDED diff --git a/src/beast/modules/beast_core/text/NewLine.h b/src/beast/beast/strings/NewLine.h similarity index 98% rename from src/beast/modules/beast_core/text/NewLine.h rename to src/beast/beast/strings/NewLine.h index d5cf0fae39..3bb4315b0a 100644 --- a/src/beast/modules/beast_core/text/NewLine.h +++ b/src/beast/beast/strings/NewLine.h @@ -24,6 +24,9 @@ #ifndef BEAST_NEWLINE_H_INCLUDED #define BEAST_NEWLINE_H_INCLUDED +#include "../Config.h" + +namespace beast { //============================================================================== /** This class is used for represent a new-line character sequence. @@ -69,5 +72,7 @@ extern NewLine newLine; */ BEAST_API String& BEAST_CALLTYPE operator<< (String& string1, const NewLine&); +} + +#endif -#endif // BEAST_NEWLINE_H_INCLUDED diff --git a/src/beast/modules/beast_core/text/String.h b/src/beast/beast/strings/String.h similarity index 98% rename from src/beast/modules/beast_core/text/String.h rename to src/beast/beast/strings/String.h index cda3173fee..c895d99ee1 100644 --- a/src/beast/modules/beast_core/text/String.h +++ b/src/beast/beast/strings/String.h @@ -21,8 +21,38 @@ */ //============================================================================== -#ifndef BEAST_STRING_H_INCLUDED -#define BEAST_STRING_H_INCLUDED +#ifndef BEAST_STRINGS_STRING_H_INCLUDED +#define BEAST_STRINGS_STRING_H_INCLUDED + +#include "../Config.h" +#include "../CStdInt.h" +#include "CharacterFunctions.h" +#if BEAST_MSVC +# pragma warning (push) +# pragma warning (disable: 4514 4996) +#endif +#include "CharPointer_UTF8.h" +#include "CharPointer_UTF16.h" +#include "CharPointer_UTF32.h" +#include "CharPointer_ASCII.h" +#if BEAST_MSVC +# pragma warning (pop) +#endif +#include "StringCharPointerType.h" +#include "StringFromNumber.h" +#include "String.h" + +#include + +namespace beast { + +#if BEAST_NATIVE_WCHAR_IS_UTF8 + typedef CharPointer_UTF8 CharPointer_wchar_t; +#elif BEAST_NATIVE_WCHAR_IS_UTF16 + typedef CharPointer_UTF16 CharPointer_wchar_t; +#else + typedef CharPointer_UTF32 CharPointer_wchar_t; +#endif //============================================================================== /** @@ -1348,8 +1378,7 @@ std::basic_ostream & BEAST_CALLTYPE operator<< (std::basic_ostr return stream << stringToWrite.toWideCharPointer(); } -/** Writes a string to an OutputStream as UTF8. */ -BEAST_API OutputStream& BEAST_CALLTYPE operator<< (OutputStream& stream, const String& stringToWrite); +} +#endif -#endif // BEAST_STRING_H_INCLUDED diff --git a/src/beast/modules/beast_core/text/StringCharPointerType.h b/src/beast/beast/strings/StringCharPointerType.h similarity index 94% rename from src/beast/modules/beast_core/text/StringCharPointerType.h rename to src/beast/beast/strings/StringCharPointerType.h index 37e82b7b25..9a5373d689 100644 --- a/src/beast/modules/beast_core/text/StringCharPointerType.h +++ b/src/beast/beast/strings/StringCharPointerType.h @@ -21,8 +21,10 @@ */ //============================================================================== -#ifndef BEAST_STRINGCHARPOINTERTYPE_H_INCLUDED -#define BEAST_STRINGCHARPOINTERTYPE_H_INCLUDED +#ifndef BEAST_STRINGS_STRINGCHARPOINTERTYPE_H_INCLUDED +#define BEAST_STRINGS_STRINGCHARPOINTERTYPE_H_INCLUDED + +namespace beast { /** This is the character encoding type used internally to store the string. @@ -50,5 +52,7 @@ typedef CharPointer_UTF8 StringCharPointerType; #endif +} + #endif diff --git a/src/beast/modules/beast_core/text/StringFromNumber.h b/src/beast/beast/strings/StringFromNumber.h similarity index 96% rename from src/beast/modules/beast_core/text/StringFromNumber.h rename to src/beast/beast/strings/StringFromNumber.h index b5f58fca81..bd2ace60d7 100644 --- a/src/beast/modules/beast_core/text/StringFromNumber.h +++ b/src/beast/beast/strings/StringFromNumber.h @@ -21,10 +21,14 @@ */ //============================================================================== -#ifndef BEAST_CORE_STRINGFROMNUMBER_H_INCLUDED -#define BEAST_CORE_STRINGFROMNUMBER_H_INCLUDED +#ifndef BEAST_STRINGS_STRINGFROMNUMBER_H_INCLUDED +#define BEAST_STRINGS_STRINGFROMNUMBER_H_INCLUDED -// This is private! +#include "../Arithmetic.h" + +namespace beast { + +// VFALCO TODO Put this in namespace detail // class NumberToStringConverters { @@ -156,4 +160,6 @@ public: } }; +} + #endif diff --git a/src/beast/beast/strings/Strings.cpp b/src/beast/beast/strings/Strings.cpp new file mode 100644 index 0000000000..d76435f800 --- /dev/null +++ b/src/beast/beast/strings/Strings.cpp @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "BeastConfig.h" + +#include "impl/CharacterFunctions.cpp" +#include "impl/String.cpp" diff --git a/src/beast/modules/beast_core/text/CharacterFunctions.cpp b/src/beast/beast/strings/impl/CharacterFunctions.cpp similarity index 98% rename from src/beast/modules/beast_core/text/CharacterFunctions.cpp rename to src/beast/beast/strings/impl/CharacterFunctions.cpp index 0f70a0a9b8..4920e7634a 100644 --- a/src/beast/modules/beast_core/text/CharacterFunctions.cpp +++ b/src/beast/beast/strings/impl/CharacterFunctions.cpp @@ -21,7 +21,12 @@ */ //============================================================================== -//============================================================================== +#include + +#include "../CharacterFunctions.h" + +namespace beast { + #if BEAST_MSVC #pragma warning (push) #pragma warning (disable: 4514 4996) @@ -147,3 +152,5 @@ double CharacterFunctions::mulexp10 (const double value, int exponent) noexcept return negative ? (value / result) : (value * result); } + +} diff --git a/src/beast/modules/beast_core/text/String.cpp b/src/beast/beast/strings/impl/String.cpp similarity index 98% rename from src/beast/modules/beast_core/text/String.cpp rename to src/beast/beast/strings/impl/String.cpp index 5b667b14f5..5f281dcaa9 100644 --- a/src/beast/modules/beast_core/text/String.cpp +++ b/src/beast/beast/strings/impl/String.cpp @@ -21,6 +21,21 @@ */ //============================================================================== +#include + +#include "../String.h" +#include "../NewLine.h" + +#include "../../ByteOrder.h" +#include "../../Memory.h" +#include "../../StaticAssert.h" +#include "../../Arithmetic.h" +#include "../../HeapBlock.h" + +#include "../../../modules/beast_core/beast_core.h" // for UnitTest + +namespace beast { + #if BEAST_MSVC #pragma warning (push) #pragma warning (disable: 4514 4996) @@ -32,14 +47,6 @@ NewLine newLine; #error "BEAST_STRINGS_ARE_UNICODE is deprecated! All strings are now unicode by default." #endif -#if BEAST_NATIVE_WCHAR_IS_UTF8 - typedef CharPointer_UTF8 CharPointer_wchar_t; -#elif BEAST_NATIVE_WCHAR_IS_UTF16 - typedef CharPointer_UTF16 CharPointer_wchar_t; -#else - typedef CharPointer_UTF32 CharPointer_wchar_t; -#endif - static inline CharPointer_wchar_t castToCharPointer_wchar_t (const void* t) noexcept { return CharPointer_wchar_t (static_cast (t)); @@ -632,23 +639,6 @@ BEAST_API String& BEAST_CALLTYPE operator<< (String& s1, const int64 number) BEAST_API String& BEAST_CALLTYPE operator<< (String& s1, const float number) { return s1 += String (number); } BEAST_API String& BEAST_CALLTYPE operator<< (String& s1, const double number) { return s1 += String (number); } -BEAST_API OutputStream& BEAST_CALLTYPE operator<< (OutputStream& stream, const String& text) -{ - const size_t numBytes = text.getNumBytesAsUTF8(); - - #if (BEAST_STRING_UTF_TYPE == 8) - stream.write (text.getCharPointer().getAddress(), numBytes); - #else - // (This avoids using toUTF8() to prevent the memory bloat that it would leave behind - // if lots of large, persistent strings were to be written to streams). - HeapBlock temp (numBytes + 1); - CharPointer_UTF8 (temp).writeAll (text.getCharPointer()); - stream.write (temp, numBytes); - #endif - - return stream; -} - BEAST_API String& BEAST_CALLTYPE operator<< (String& string1, const NewLine&) { return string1 += NewLine::getDefault(); @@ -1973,6 +1963,8 @@ String String::fromUTF8 (const char* const buffer, int bufferSizeBytes) //============================================================================== //============================================================================== +#ifdef BEAST_UNITTEST_H_INCLUDED + class StringTests : public UnitTest { public: @@ -2326,3 +2318,6 @@ public: static StringTests stringUnitTests; +#endif + +} diff --git a/src/beast/modules/beast_asio/beast_asio.cpp b/src/beast/modules/beast_asio/beast_asio.cpp index 0946982532..1df4f9d6ab 100644 --- a/src/beast/modules/beast_asio/beast_asio.cpp +++ b/src/beast/modules/beast_asio/beast_asio.cpp @@ -23,8 +23,9 @@ #include "beast_asio.h" -namespace beast -{ +namespace beast { + +# include "../../beast/http/impl/http-parser/http_parser.h" #include "async/SharedHandler.cpp" @@ -37,10 +38,8 @@ namespace beast #include "protocol/HandshakeDetectLogicPROXY.cpp" -# include "parsehttp/http_parser.h" # include "http/HTTPParserImpl.h" #include "http/HTTPParser.cpp" -#include "http/UniformResourceLocator.cpp" #include "http/HTTPClientType.cpp" #include "http/HTTPField.cpp" #include "http/HTTPHeaders.cpp" @@ -61,16 +60,4 @@ namespace beast #include "system/BoostUnitTests.cpp" -#ifdef _MSC_VER -#pragma warning (push) -#pragma warning (disable: 4127) // conditional expression is constant -#pragma warning (disable: 4244) // integer conversion, possible loss of data -#endif -#include "parsehttp/http_parser.c" -#ifdef _MSC_VER -#pragma warning (pop) -#endif - } - -//------------------------------------------------------------------------------ diff --git a/src/beast/modules/beast_asio/beast_asio.h b/src/beast/modules/beast_asio/beast_asio.h index 637f3e7068..ecf7efda8e 100644 --- a/src/beast/modules/beast_asio/beast_asio.h +++ b/src/beast/modules/beast_asio/beast_asio.h @@ -55,6 +55,7 @@ #include "../../beast/MPL.h" #include "../../beast/Utility.h" +#include "../../beast/HTTP.h" namespace beast { @@ -87,7 +88,6 @@ namespace beast # include "http/HTTPRequest.h" # include "http/HTTPResponse.h" # include "http/HTTPParser.h" -# include "http/UniformResourceLocator.h" #include "http/HTTPClientType.h" # include "protocol/InputParser.h" diff --git a/src/beast/modules/beast_asio/http/HTTPClientType.cpp b/src/beast/modules/beast_asio/http/HTTPClientType.cpp index d1e1dd98ed..c35c1a12c6 100644 --- a/src/beast/modules/beast_asio/http/HTTPClientType.cpp +++ b/src/beast/modules/beast_asio/http/HTTPClientType.cpp @@ -87,7 +87,7 @@ public: return m_result; } - Result const& get (UniformResourceLocator const& url) + Result const& get (URL const& url) { boost::asio::io_service io_service; async_get (io_service, nullptr, url); @@ -98,7 +98,7 @@ public: //-------------------------------------------------------------------------- void async_get (boost::asio::io_service& io_service, Listener* listener, - UniformResourceLocator const& url) + URL const& url) { async_get (io_service, url, ListenerHandler (this, listener)); } @@ -107,7 +107,7 @@ public: // template void async_get (boost::asio::io_service& io_service, - UniformResourceLocator const& url, + URL const& url, BOOST_ASIO_MOVE_ARG(Handler) handler) { async_get (io_service, url, newErrorHandler ( @@ -115,7 +115,7 @@ public: } void async_get (boost::asio::io_service& io_service, - UniformResourceLocator const& url, SharedHandlerPtr handler) + URL const& url, SharedHandlerPtr handler) { // This automatically dispatches m_async_op = new AsyncGetOp ( @@ -143,7 +143,7 @@ private: /** Helper function to fill out a Query from a URL. */ template - static Query queryFromURL (UniformResourceLocator const& url) + static Query queryFromURL (URL const& url) { if (url.port () != 0) { @@ -206,7 +206,7 @@ private: public: AsyncGetOp (HTTPClientType& owner, boost::asio::io_service& io_service, - UniformResourceLocator const& url, + URL const& url, SharedHandlerPtr const& handler, double timeoutSeconds, std::size_t messageLimitBytes, @@ -688,7 +688,7 @@ private: HTTPClientType& m_owner; boost::asio::io_service& m_io_service; boost::asio::io_service& m_strand; - UniformResourceLocator m_url; + URL m_url; SharedHandlerPtr m_handler; boost::asio::deadline_timer m_timer; resolver m_resolver; diff --git a/src/beast/modules/beast_asio/http/HTTPClientType.h b/src/beast/modules/beast_asio/http/HTTPClientType.h index 5922813f38..db7982ae0b 100644 --- a/src/beast/modules/beast_asio/http/HTTPClientType.h +++ b/src/beast/modules/beast_asio/http/HTTPClientType.h @@ -47,11 +47,11 @@ public: virtual Result const& result () const = 0; virtual Result const& get ( - UniformResourceLocator const& url) = 0; + URL const& url) = 0; virtual void async_get (boost::asio::io_service& io_service, Listener* listener, - UniformResourceLocator const& url) = 0; + URL const& url) = 0; /** Cancel any pending asynchronous operations. This must be called before destroying the container if there are diff --git a/src/beast/modules/beast_asio/parsehttp/.gitignore b/src/beast/modules/beast_asio/parsehttp/.gitignore deleted file mode 100644 index 5d12d158a6..0000000000 --- a/src/beast/modules/beast_asio/parsehttp/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -/out/ -core -tags -*.o -test -test_g -test_fast -url_parser -parsertrace -parsertrace_g -*.mk -*.Makefile -*.so.* -*.a diff --git a/src/beast/modules/beast_asio/parsehttp/.mailmap b/src/beast/modules/beast_asio/parsehttp/.mailmap deleted file mode 100644 index 75a187c568..0000000000 --- a/src/beast/modules/beast_asio/parsehttp/.mailmap +++ /dev/null @@ -1,7 +0,0 @@ -# update AUTHORS with: -# git log --all --reverse --format='%aN <%aE>' | perl -ne 'BEGIN{print "# Authors ordered by first contribution.\n"} print unless $h{$_}; $h{$_} = 1' > AUTHORS -Ryan Dahl -Salman Haq -Simon Zimmermann -Thomas LE ROUX LE ROUX Thomas -Thomas LE ROUX Thomas LE ROUX diff --git a/src/beast/modules/beast_asio/parsehttp/.travis.yml b/src/beast/modules/beast_asio/parsehttp/.travis.yml deleted file mode 100644 index ae85af020a..0000000000 --- a/src/beast/modules/beast_asio/parsehttp/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: c - -compiler: - - clang - - gcc - -script: - - "make" - -notifications: - email: false - irc: - - "irc.freenode.net#libuv" diff --git a/src/beast/modules/beast_asio/parsehttp/AUTHORS b/src/beast/modules/beast_asio/parsehttp/AUTHORS deleted file mode 100644 index 92ee45cad6..0000000000 --- a/src/beast/modules/beast_asio/parsehttp/AUTHORS +++ /dev/null @@ -1,41 +0,0 @@ -# Authors ordered by first contribution. -Ryan Dahl -Jeremy Hinegardner -Sergey Shepelev -Joe Damato -tomika -Phoenix Sol -Cliff Frey -Ewen Cheslack-Postava -Santiago Gala -Tim Becker -Jeff Terrace -Ben Noordhuis -Nathan Rajlich -Mark Nottingham -Aman Gupta -Tim Becker -Sean Cunningham -Peter Griess -Salman Haq -Cliff Frey -Jon Kolb -Fouad Mardini -Paul Querna -Felix Geisendörfer -koichik -Andre Caron -Ivo Raisr -James McLaughlin -David Gwynne -Thomas LE ROUX -Randy Rizun -Andre Louis Caron -Simon Zimmermann -Erik Dubbelboer -Martell Malone -Bertrand Paquet -BogDan Vatra -Peter Faiman -Corey Richardson -Tóth Tamás diff --git a/src/beast/modules/beast_asio/parsehttp/CONTRIBUTIONS b/src/beast/modules/beast_asio/parsehttp/CONTRIBUTIONS deleted file mode 100644 index 11ba31e4b9..0000000000 --- a/src/beast/modules/beast_asio/parsehttp/CONTRIBUTIONS +++ /dev/null @@ -1,4 +0,0 @@ -Contributors must agree to the Contributor License Agreement before patches -can be accepted. - -http://spreadsheets2.google.com/viewform?hl=en&formkey=dDJXOGUwbzlYaWM4cHN1MERwQS1CSnc6MQ diff --git a/src/beast/modules/beast_asio/parsehttp/LICENSE-MIT b/src/beast/modules/beast_asio/parsehttp/LICENSE-MIT deleted file mode 100644 index 58010b3889..0000000000 --- a/src/beast/modules/beast_asio/parsehttp/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -http_parser.c is based on src/http/ngx_http_parse.c from NGINX copyright -Igor Sysoev. - -Additional changes are licensed under the same terms as NGINX and -copyright Joyent, Inc. and other Node contributors. All rights reserved. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. diff --git a/src/beast/modules/beast_asio/parsehttp/Makefile b/src/beast/modules/beast_asio/parsehttp/Makefile deleted file mode 100644 index 02182b10cf..0000000000 --- a/src/beast/modules/beast_asio/parsehttp/Makefile +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright Joyent, Inc. and other Node contributors. All rights reserved. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -# IN THE SOFTWARE. - -PLATFORM ?= $(shell sh -c 'uname -s | tr "[A-Z]" "[a-z]"') -SONAME ?= libhttp_parser.so.2.1 - -CC?=gcc -AR?=ar - -CPPFLAGS += -I. -CPPFLAGS_DEBUG = $(CPPFLAGS) -DHTTP_PARSER_STRICT=1 -CPPFLAGS_DEBUG += $(CPPFLAGS_DEBUG_EXTRA) -CPPFLAGS_FAST = $(CPPFLAGS) -DHTTP_PARSER_STRICT=0 -CPPFLAGS_FAST += $(CPPFLAGS_FAST_EXTRA) - -CFLAGS += -Wall -Wextra -Werror -CFLAGS_DEBUG = $(CFLAGS) -O0 -g $(CFLAGS_DEBUG_EXTRA) -CFLAGS_FAST = $(CFLAGS) -O3 $(CFLAGS_FAST_EXTRA) -CFLAGS_LIB = $(CFLAGS_FAST) -fPIC - -LDFLAGS_LIB = $(LDFLAGS) -shared - -ifneq (darwin,$(PLATFORM)) -# TODO(bnoordhuis) The native SunOS linker expects -h rather than -soname... -LDFLAGS_LIB += -Wl,-soname=$(SONAME) -endif - -test: test_g test_fast - ./test_g - ./test_fast - -test_g: http_parser_g.o test_g.o - $(CC) $(CFLAGS_DEBUG) $(LDFLAGS) http_parser_g.o test_g.o -o $@ - -test_g.o: test.c http_parser.h Makefile - $(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) -c test.c -o $@ - -http_parser_g.o: http_parser.c http_parser.h Makefile - $(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) -c http_parser.c -o $@ - -test_fast: http_parser.o test.o http_parser.h - $(CC) $(CFLAGS_FAST) $(LDFLAGS) http_parser.o test.o -o $@ - -test.o: test.c http_parser.h Makefile - $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) -c test.c -o $@ - -http_parser.o: http_parser.c http_parser.h Makefile - $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) -c http_parser.c - -test-run-timed: test_fast - while(true) do time ./test_fast > /dev/null; done - -test-valgrind: test_g - valgrind ./test_g - -libhttp_parser.o: http_parser.c http_parser.h Makefile - $(CC) $(CPPFLAGS_FAST) $(CFLAGS_LIB) -c http_parser.c -o libhttp_parser.o - -library: libhttp_parser.o - $(CC) $(LDFLAGS_LIB) -o $(SONAME) $< - -package: http_parser.o - $(AR) rcs libhttp_parser.a http_parser.o - -url_parser: http_parser.o contrib/url_parser.c - $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) $^ -o $@ - -url_parser_g: http_parser_g.o contrib/url_parser.c - $(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) $^ -o $@ - -parsertrace: http_parser.o contrib/parsertrace.c - $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) $^ -o parsertrace - -parsertrace_g: http_parser_g.o contrib/parsertrace.c - $(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) $^ -o parsertrace_g - -tags: http_parser.c http_parser.h test.c - ctags $^ - -clean: - rm -f *.o *.a tags test test_fast test_g \ - http_parser.tar libhttp_parser.so.* \ - url_parser url_parser_g parsertrace parsertrace_g - -contrib/url_parser.c: http_parser.h -contrib/parsertrace.c: http_parser.h - -.PHONY: clean package test-run test-run-timed test-valgrind diff --git a/src/beast/modules/beast_asio/parsehttp/README.md b/src/beast/modules/beast_asio/parsehttp/README.md deleted file mode 100644 index b63418af84..0000000000 --- a/src/beast/modules/beast_asio/parsehttp/README.md +++ /dev/null @@ -1,180 +0,0 @@ -HTTP Parser -=========== - -[![Build Status](https://travis-ci.org/joyent/http-parser.png?branch=master)](https://travis-ci.org/joyent/http-parser) - -This is a parser for HTTP messages written in C. It parses both requests and -responses. The parser is designed to be used in performance HTTP -applications. It does not make any syscalls nor allocations, it does not -buffer data, it can be interrupted at anytime. Depending on your -architecture, it only requires about 40 bytes of data per message -stream (in a web server that is per connection). - -Features: - - * No dependencies - * Handles persistent streams (keep-alive). - * Decodes chunked encoding. - * Upgrade support - * Defends against buffer overflow attacks. - -The parser extracts the following information from HTTP messages: - - * Header fields and values - * Content-Length - * Request method - * Response status code - * Transfer-Encoding - * HTTP version - * Request URL - * Message body - - -Usage ------ - -One `http_parser` object is used per TCP connection. Initialize the struct -using `http_parser_init()` and set the callbacks. That might look something -like this for a request parser: - - http_parser_settings settings; - settings.on_url = my_url_callback; - settings.on_header_field = my_header_field_callback; - /* ... */ - - http_parser *parser = malloc(sizeof(http_parser)); - http_parser_init(parser, HTTP_REQUEST); - parser->data = my_socket; - -When data is received on the socket execute the parser and check for errors. - - size_t len = 80*1024, nparsed; - char buf[len]; - ssize_t recved; - - recved = recv(fd, buf, len, 0); - - if (recved < 0) { - /* Handle error. */ - } - - /* Start up / continue the parser. - * Note we pass recved==0 to signal that EOF has been recieved. - */ - nparsed = http_parser_execute(parser, &settings, buf, recved); - - if (parser->upgrade) { - /* handle new protocol */ - } else if (nparsed != recved) { - /* Handle error. Usually just close the connection. */ - } - -HTTP needs to know where the end of the stream is. For example, sometimes -servers send responses without Content-Length and expect the client to -consume input (for the body) until EOF. To tell http_parser about EOF, give -`0` as the forth parameter to `http_parser_execute()`. Callbacks and errors -can still be encountered during an EOF, so one must still be prepared -to receive them. - -Scalar valued message information such as `status_code`, `method`, and the -HTTP version are stored in the parser structure. This data is only -temporally stored in `http_parser` and gets reset on each new message. If -this information is needed later, copy it out of the structure during the -`headers_complete` callback. - -The parser decodes the transfer-encoding for both requests and responses -transparently. That is, a chunked encoding is decoded before being sent to -the on_body callback. - - -The Special Problem of Upgrade ------------------------------- - -HTTP supports upgrading the connection to a different protocol. An -increasingly common example of this is the Web Socket protocol which sends -a request like - - GET /demo HTTP/1.1 - Upgrade: WebSocket - Connection: Upgrade - Host: example.com - Origin: http://example.com - WebSocket-Protocol: sample - -followed by non-HTTP data. - -(See http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75 for more -information the Web Socket protocol.) - -To support this, the parser will treat this as a normal HTTP message without a -body. Issuing both on_headers_complete and on_message_complete callbacks. However -http_parser_execute() will stop parsing at the end of the headers and return. - -The user is expected to check if `parser->upgrade` has been set to 1 after -`http_parser_execute()` returns. Non-HTTP data begins at the buffer supplied -offset by the return value of `http_parser_execute()`. - - -Callbacks ---------- - -During the `http_parser_execute()` call, the callbacks set in -`http_parser_settings` will be executed. The parser maintains state and -never looks behind, so buffering the data is not necessary. If you need to -save certain data for later usage, you can do that from the callbacks. - -There are two types of callbacks: - -* notification `typedef int (*http_cb) (http_parser*);` - Callbacks: on_message_begin, on_headers_complete, on_message_complete. -* data `typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);` - Callbacks: (requests only) on_uri, - (common) on_header_field, on_header_value, on_body; - -Callbacks must return 0 on success. Returning a non-zero value indicates -error to the parser, making it exit immediately. - -In case you parse HTTP message in chunks (i.e. `read()` request line -from socket, parse, read half headers, parse, etc) your data callbacks -may be called more than once. Http-parser guarantees that data pointer is only -valid for the lifetime of callback. You can also `read()` into a heap allocated -buffer to avoid copying memory around if this fits your application. - -Reading headers may be a tricky task if you read/parse headers partially. -Basically, you need to remember whether last header callback was field or value -and apply following logic: - - (on_header_field and on_header_value shortened to on_h_*) - ------------------------ ------------ -------------------------------------------- - | State (prev. callback) | Callback | Description/action | - ------------------------ ------------ -------------------------------------------- - | nothing (first call) | on_h_field | Allocate new buffer and copy callback data | - | | | into it | - ------------------------ ------------ -------------------------------------------- - | value | on_h_field | New header started. | - | | | Copy current name,value buffers to headers | - | | | list and allocate new buffer for new name | - ------------------------ ------------ -------------------------------------------- - | field | on_h_field | Previous name continues. Reallocate name | - | | | buffer and append callback data to it | - ------------------------ ------------ -------------------------------------------- - | field | on_h_value | Value for current header started. Allocate | - | | | new buffer and copy callback data to it | - ------------------------ ------------ -------------------------------------------- - | value | on_h_value | Value continues. Reallocate value buffer | - | | | and append callback data to it | - ------------------------ ------------ -------------------------------------------- - - -Parsing URLs ------------- - -A simplistic zero-copy URL parser is provided as `http_parser_parse_url()`. -Users of this library may wish to use it to parse URLs constructed from -consecutive `on_url` callbacks. - -See examples of reading in headers: - -* [partial example](http://gist.github.com/155877) in C -* [from http-parser tests](http://github.com/joyent/http-parser/blob/37a0ff8/test.c#L403) in C -* [from Node library](http://github.com/joyent/node/blob/842eaf4/src/http.js#L284) in Javascript diff --git a/src/beast/modules/beast_asio/parsehttp/contrib/parsertrace.c b/src/beast/modules/beast_asio/parsehttp/contrib/parsertrace.c deleted file mode 100644 index c9bc71ec01..0000000000 --- a/src/beast/modules/beast_asio/parsehttp/contrib/parsertrace.c +++ /dev/null @@ -1,156 +0,0 @@ -/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev - * - * Additional changes are licensed under the same terms as NGINX and - * copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ - -/* Dump what the parser finds to stdout as it happen */ - -#include "http_parser.h" -#include -#include -#include - -int on_message_begin(http_parser* _) { - (void)_; - printf("\n***MESSAGE BEGIN***\n\n"); - return 0; -} - -int on_headers_complete(http_parser* _) { - (void)_; - printf("\n***HEADERS COMPLETE***\n\n"); - return 0; -} - -int on_message_complete(http_parser* _) { - (void)_; - printf("\n***MESSAGE COMPLETE***\n\n"); - return 0; -} - -int on_url(http_parser* _, const char* at, size_t length) { - (void)_; - printf("Url: %.*s\n", (int)length, at); - return 0; -} - -int on_header_field(http_parser* _, const char* at, size_t length) { - (void)_; - printf("Header field: %.*s\n", (int)length, at); - return 0; -} - -int on_header_value(http_parser* _, const char* at, size_t length) { - (void)_; - printf("Header value: %.*s\n", (int)length, at); - return 0; -} - -int on_body(http_parser* _, const char* at, size_t length) { - (void)_; - printf("Body: %.*s\n", (int)length, at); - return 0; -} - -void usage(const char* name) { - fprintf(stderr, - "Usage: %s $type $filename\n" - " type: -x, where x is one of {r,b,q}\n" - " parses file as a Response, reQuest, or Both\n", - name); - exit(EXIT_FAILURE); -} - -int main(int argc, char* argv[]) { - enum http_parser_type file_type; - - if (argc != 3) { - usage(argv[0]); - } - - char* type = argv[1]; - if (type[0] != '-') { - usage(argv[0]); - } - - switch (type[1]) { - /* in the case of "-", type[1] will be NUL */ - case 'r': - file_type = HTTP_RESPONSE; - break; - case 'q': - file_type = HTTP_REQUEST; - break; - case 'b': - file_type = HTTP_BOTH; - break; - default: - usage(argv[0]); - } - - char* filename = argv[2]; - FILE* file = fopen(filename, "r"); - if (file == NULL) { - perror("fopen"); - return EXIT_FAILURE; - } - - fseek(file, 0, SEEK_END); - long file_length = ftell(file); - if (file_length == -1) { - perror("ftell"); - return EXIT_FAILURE; - } - fseek(file, 0, SEEK_SET); - - char* data = malloc(file_length); - if (fread(data, 1, file_length, file) != (size_t)file_length) { - fprintf(stderr, "couldn't read entire file\n"); - free(data); - return EXIT_FAILURE; - } - - http_parser_settings settings; - memset(&settings, 0, sizeof(settings)); - settings.on_message_begin = on_message_begin; - settings.on_url = on_url; - settings.on_header_field = on_header_field; - settings.on_header_value = on_header_value; - settings.on_headers_complete = on_headers_complete; - settings.on_body = on_body; - settings.on_message_complete = on_message_complete; - - http_parser parser; - http_parser_init(&parser, file_type); - size_t nparsed = http_parser_execute(&parser, &settings, data, file_length); - free(data); - - if (nparsed != (size_t)file_length) { - fprintf(stderr, - "Error: %s (%s)\n", - http_errno_description(HTTP_PARSER_ERRNO(&parser)), - http_errno_name(HTTP_PARSER_ERRNO(&parser))); - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; -} diff --git a/src/beast/modules/beast_asio/parsehttp/contrib/url_parser.c b/src/beast/modules/beast_asio/parsehttp/contrib/url_parser.c deleted file mode 100644 index b1f9c979f2..0000000000 --- a/src/beast/modules/beast_asio/parsehttp/contrib/url_parser.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "http_parser.h" -#include -#include - -void -dump_url (const char *url, const struct http_parser_url *u) -{ - unsigned int i; - - printf("\tfield_set: 0x%x, port: %u\n", u->field_set, u->port); - for (i = 0; i < UF_MAX; i++) { - if ((u->field_set & (1 << i)) == 0) { - printf("\tfield_data[%u]: unset\n", i); - continue; - } - - printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n", - i, - u->field_data[i].off, - u->field_data[i].len, - u->field_data[i].len, - url + u->field_data[i].off); - } -} - -int main(int argc, char ** argv) { - if (argc != 3) { - printf("Syntax : %s connect|get url\n", argv[0]); - return 1; - } - struct http_parser_url u; - int len = strlen(argv[2]); - int connect = strcmp("connect", argv[1]) == 0 ? 1 : 0; - printf("Parsing %s, connect %d\n", argv[2], connect); - - int result = http_parser_parse_url(argv[2], len, connect, &u); - if (result != 0) { - printf("Parse error : %d\n", result); - return result; - } - printf("Parse ok, result : \n"); - dump_url(argv[2], &u); - return 0; -} \ No newline at end of file diff --git a/src/beast/modules/beast_asio/parsehttp/http_parser.c b/src/beast/modules/beast_asio/parsehttp/http_parser.c deleted file mode 100644 index c87186f35e..0000000000 --- a/src/beast/modules/beast_asio/parsehttp/http_parser.c +++ /dev/null @@ -1,2199 +0,0 @@ -/* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev - * - * Additional changes are licensed under the same terms as NGINX and - * copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include "http_parser.h" -#include -#include -#include -#include -#include -#include - -#ifndef ULLONG_MAX -# define ULLONG_MAX ((uint64_t) -1) /* 2^64-1 */ -#endif - -#ifndef MIN -# define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -#ifndef ARRAY_SIZE -# define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) -#endif - -#ifndef BIT_AT -# define BIT_AT(a, i) \ - (!!((unsigned int) (a)[(unsigned int) (i) >> 3] & \ - (1 << ((unsigned int) (i) & 7)))) -#endif - -#ifndef ELEM_AT -# define ELEM_AT(a, i, v) ((unsigned int) (i) < ARRAY_SIZE(a) ? (a)[(i)] : (v)) -#endif - -#define SET_ERRNO(e) \ -do { \ - parser->http_errno = (e); \ -} while(0) - - -/* Run the notify callback FOR, returning ER if it fails */ -#define CALLBACK_NOTIFY_(FOR, ER) \ -do { \ - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ - \ - if (settings->on_##FOR) { \ - if (0 != settings->on_##FOR(parser)) { \ - SET_ERRNO(HPE_CB_##FOR); \ - } \ - \ - /* We either errored above or got paused; get out */ \ - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \ - return (ER); \ - } \ - } \ -} while (0) - -/* Run the notify callback FOR and consume the current byte */ -#define CALLBACK_NOTIFY(FOR) CALLBACK_NOTIFY_(FOR, p - data + 1) - -/* Run the notify callback FOR and don't consume the current byte */ -#define CALLBACK_NOTIFY_NOADVANCE(FOR) CALLBACK_NOTIFY_(FOR, p - data) - -/* Run data callback FOR with LEN bytes, returning ER if it fails */ -#define CALLBACK_DATA_(FOR, LEN, ER) \ -do { \ - assert(HTTP_PARSER_ERRNO(parser) == HPE_OK); \ - \ - if (FOR##_mark) { \ - if (settings->on_##FOR) { \ - if (0 != settings->on_##FOR(parser, FOR##_mark, (LEN))) { \ - SET_ERRNO(HPE_CB_##FOR); \ - } \ - \ - /* We either errored above or got paused; get out */ \ - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { \ - return (ER); \ - } \ - } \ - FOR##_mark = NULL; \ - } \ -} while (0) - -/* Run the data callback FOR and consume the current byte */ -#define CALLBACK_DATA(FOR) \ - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) - -/* Run the data callback FOR and don't consume the current byte */ -#define CALLBACK_DATA_NOADVANCE(FOR) \ - CALLBACK_DATA_(FOR, p - FOR##_mark, p - data) - -/* Set the mark FOR; non-destructive if mark is already set */ -#define MARK(FOR) \ -do { \ - if (!FOR##_mark) { \ - FOR##_mark = p; \ - } \ -} while (0) - - -#define PROXY_CONNECTION "proxy-connection" -#define CONNECTION "connection" -#define CONTENT_LENGTH "content-length" -#define TRANSFER_ENCODING "transfer-encoding" -#define UPGRADE "upgrade" -#define CHUNKED "chunked" -#define KEEP_ALIVE "keep-alive" -#define CLOSE "close" - - -static const char *method_strings[] = - { -#define XX(num, name, string) #string, - HTTP_METHOD_MAP(XX) -#undef XX - }; - - -/* Tokens as defined by rfc 2616. Also lowercases them. - * token = 1* - * separators = "(" | ")" | "<" | ">" | "@" - * | "," | ";" | ":" | "\" | <"> - * | "/" | "[" | "]" | "?" | "=" - * | "{" | "}" | SP | HT - */ -static const char tokens[256] = { -/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0, 0, 0, 0, 0, 0, 0, 0, -/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0, '!', 0, '#', '$', '%', '&', '\'', -/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 0, 0, '*', '+', 0, '-', '.', 0, -/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - '0', '1', '2', '3', '4', '5', '6', '7', -/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - '8', '9', 0, 0, 0, 0, 0, 0, -/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', -/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', -/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 'x', 'y', 'z', 0, 0, 0, '^', '_', -/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', -/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', -/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', -/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 'x', 'y', 'z', 0, '|', 0, '~', 0 }; - - -static const int8_t unhex[256] = - {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - }; - - -#if HTTP_PARSER_STRICT -# define T(v) 0 -#else -# define T(v) v -#endif - - -static const uint8_t normal_url_char[32] = { -/* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0 | T(2) | 0 | 0 | T(16) | 0 | 0 | 0, -/* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0, -/* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0 | 2 | 4 | 0 | 16 | 32 | 64 | 128, -/* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, -/* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, -/* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 1 | 2 | 4 | 8 | 16 | 32 | 64 | 0, }; - -#undef T - -enum state - { s_dead = 1 /* important that this is > 0 */ - - , s_start_req_or_res - , s_res_or_resp_H - , s_start_res - , s_res_H - , s_res_HT - , s_res_HTT - , s_res_HTTP - , s_res_first_http_major - , s_res_http_major - , s_res_first_http_minor - , s_res_http_minor - , s_res_first_status_code - , s_res_status_code - , s_res_status - , s_res_line_almost_done - - , s_start_req - - , s_req_method - , s_req_spaces_before_url - , s_req_schema - , s_req_schema_slash - , s_req_schema_slash_slash - , s_req_server_start - , s_req_server - , s_req_server_with_at - , s_req_path - , s_req_query_string_start - , s_req_query_string - , s_req_fragment_start - , s_req_fragment - , s_req_http_start - , s_req_http_H - , s_req_http_HT - , s_req_http_HTT - , s_req_http_HTTP - , s_req_first_http_major - , s_req_http_major - , s_req_first_http_minor - , s_req_http_minor - , s_req_line_almost_done - - , s_header_field_start - , s_header_field - , s_header_value_start - , s_header_value - , s_header_value_lws - - , s_header_almost_done - - , s_chunk_size_start - , s_chunk_size - , s_chunk_parameters - , s_chunk_size_almost_done - - , s_headers_almost_done - , s_headers_done - - /* Important: 's_headers_done' must be the last 'header' state. All - * states beyond this must be 'body' states. It is used for overflow - * checking. See the PARSING_HEADER() macro. - */ - - , s_chunk_data - , s_chunk_data_almost_done - , s_chunk_data_done - - , s_body_identity - , s_body_identity_eof - - , s_message_done - }; - - -#define PARSING_HEADER(state) (state <= s_headers_done) - - -enum header_states - { h_general = 0 - , h_C - , h_CO - , h_CON - - , h_matching_connection - , h_matching_proxy_connection - , h_matching_content_length - , h_matching_transfer_encoding - , h_matching_upgrade - - , h_connection - , h_content_length - , h_transfer_encoding - , h_upgrade - - , h_matching_transfer_encoding_chunked - , h_matching_connection_keep_alive - , h_matching_connection_close - - , h_transfer_encoding_chunked - , h_connection_keep_alive - , h_connection_close - }; - -enum http_host_state - { - s_http_host_dead = 1 - , s_http_userinfo_start - , s_http_userinfo - , s_http_host_start - , s_http_host_v6_start - , s_http_host - , s_http_host_v6 - , s_http_host_v6_end - , s_http_host_port_start - , s_http_host_port -}; - -/* Macros for character classes; depends on strict-mode */ -#define CR '\r' -#define LF '\n' -#define LOWER(c) (unsigned char)(c | 0x20) -#define IS_ALPHA(c) (LOWER(c) >= 'a' && LOWER(c) <= 'z') -#define IS_NUM(c) ((c) >= '0' && (c) <= '9') -#define IS_ALPHANUM(c) (IS_ALPHA(c) || IS_NUM(c)) -#define IS_HEX(c) (IS_NUM(c) || (LOWER(c) >= 'a' && LOWER(c) <= 'f')) -#define IS_MARK(c) ((c) == '-' || (c) == '_' || (c) == '.' || \ - (c) == '!' || (c) == '~' || (c) == '*' || (c) == '\'' || (c) == '(' || \ - (c) == ')') -#define IS_USERINFO_CHAR(c) (IS_ALPHANUM(c) || IS_MARK(c) || (c) == '%' || \ - (c) == ';' || (c) == ':' || (c) == '&' || (c) == '=' || (c) == '+' || \ - (c) == '$' || (c) == ',') - -#if HTTP_PARSER_STRICT -#define TOKEN(c) (tokens[(unsigned char)c]) -#define IS_URL_CHAR(c) (BIT_AT(normal_url_char, (unsigned char)c)) -#define IS_HOST_CHAR(c) (IS_ALPHANUM(c) || (c) == '.' || (c) == '-') -#else -#define TOKEN(c) ((c == ' ') ? ' ' : tokens[(unsigned char)c]) -#define IS_URL_CHAR(c) \ - (BIT_AT(normal_url_char, (unsigned char)c) || ((c) & 0x80)) -#define IS_HOST_CHAR(c) \ - (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') -#endif - - -#define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) - - -#if HTTP_PARSER_STRICT -# define STRICT_CHECK(cond) \ -do { \ - if (cond) { \ - SET_ERRNO(HPE_STRICT); \ - goto error; \ - } \ -} while (0) -# define NEW_MESSAGE() (http_should_keep_alive(parser) ? start_state : s_dead) -#else -# define STRICT_CHECK(cond) -# define NEW_MESSAGE() start_state -#endif - - -/* Map errno values to strings for human-readable output */ -#define HTTP_STRERROR_GEN(n, s) { "HPE_" #n, s }, -static struct { - const char *name; - const char *description; -} http_strerror_tab[] = { - HTTP_ERRNO_MAP(HTTP_STRERROR_GEN) -}; -#undef HTTP_STRERROR_GEN - -int http_message_needs_eof(const http_parser *parser); - -/* Our URL parser. - * - * This is designed to be shared by http_parser_execute() for URL validation, - * hence it has a state transition + byte-for-byte interface. In addition, it - * is meant to be embedded in http_parser_parse_url(), which does the dirty - * work of turning state transitions URL components for its API. - * - * This function should only be invoked with non-space characters. It is - * assumed that the caller cares about (and can detect) the transition between - * URL and non-URL states by looking for these. - */ -static enum state -parse_url_char(enum state s, const char ch) -{ - if (ch == ' ' || ch == '\r' || ch == '\n') { - return s_dead; - } - -#if HTTP_PARSER_STRICT - if (ch == '\t' || ch == '\f') { - return s_dead; - } -#endif - - switch (s) { - case s_req_spaces_before_url: - /* Proxied requests are followed by scheme of an absolute URI (alpha). - * All methods except CONNECT are followed by '/' or '*'. - */ - - if (ch == '/' || ch == '*') { - return s_req_path; - } - - if (IS_ALPHA(ch)) { - return s_req_schema; - } - - break; - - case s_req_schema: - if (IS_ALPHA(ch)) { - return s; - } - - if (ch == ':') { - return s_req_schema_slash; - } - - break; - - case s_req_schema_slash: - if (ch == '/') { - return s_req_schema_slash_slash; - } - - break; - - case s_req_schema_slash_slash: - if (ch == '/') { - return s_req_server_start; - } - - break; - - case s_req_server_with_at: - if (ch == '@') { - return s_dead; - } - - /* FALLTHROUGH */ - case s_req_server_start: - case s_req_server: - if (ch == '/') { - return s_req_path; - } - - if (ch == '?') { - return s_req_query_string_start; - } - - if (ch == '@') { - return s_req_server_with_at; - } - - if (IS_USERINFO_CHAR(ch) || ch == '[' || ch == ']') { - return s_req_server; - } - - break; - - case s_req_path: - if (IS_URL_CHAR(ch)) { - return s; - } - - switch (ch) { - case '?': - return s_req_query_string_start; - - case '#': - return s_req_fragment_start; - } - - break; - - case s_req_query_string_start: - case s_req_query_string: - if (IS_URL_CHAR(ch)) { - return s_req_query_string; - } - - switch (ch) { - case '?': - /* allow extra '?' in query string */ - return s_req_query_string; - - case '#': - return s_req_fragment_start; - } - - break; - - case s_req_fragment_start: - if (IS_URL_CHAR(ch)) { - return s_req_fragment; - } - - switch (ch) { - case '?': - return s_req_fragment; - - case '#': - return s; - } - - break; - - case s_req_fragment: - if (IS_URL_CHAR(ch)) { - return s; - } - - switch (ch) { - case '?': - case '#': - return s; - } - - break; - - default: - break; - } - - /* We should never fall out of the switch above unless there's an error */ - return s_dead; -} - -size_t http_parser_execute (http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len) -{ - char c, ch; - int8_t unhex_val; - const char *p = data; - const char *header_field_mark = 0; - const char *header_value_mark = 0; - const char *url_mark = 0; - const char *body_mark = 0; - - /* We're in an error state. Don't bother doing anything. */ - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { - return 0; - } - - if (len == 0) { - switch (parser->state) { - case s_body_identity_eof: - /* Use of CALLBACK_NOTIFY() here would erroneously return 1 byte read if - * we got paused. - */ - CALLBACK_NOTIFY_NOADVANCE(message_complete); - return 0; - - case s_dead: - case s_start_req_or_res: - case s_start_res: - case s_start_req: - return 0; - - default: - SET_ERRNO(HPE_INVALID_EOF_STATE); - return 1; - } - } - - - if (parser->state == s_header_field) - header_field_mark = data; - if (parser->state == s_header_value) - header_value_mark = data; - switch (parser->state) { - case s_req_path: - case s_req_schema: - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - case s_req_server: - case s_req_server_with_at: - case s_req_query_string_start: - case s_req_query_string: - case s_req_fragment_start: - case s_req_fragment: - url_mark = data; - break; - } - - for (p=data; p != data + len; p++) { - ch = *p; - - if (PARSING_HEADER(parser->state)) { - ++parser->nread; - /* Buffer overflow attack */ - if (parser->nread > HTTP_MAX_HEADER_SIZE) { - SET_ERRNO(HPE_HEADER_OVERFLOW); - goto error; - } - } - - reexecute_byte: - switch (parser->state) { - - case s_dead: - /* this state is used after a 'Connection: close' message - * the parser will error out if it reads another message - */ - if (ch == CR || ch == LF) - break; - - SET_ERRNO(HPE_CLOSED_CONNECTION); - goto error; - - case s_start_req_or_res: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (ch == 'H') { - parser->state = s_res_or_resp_H; - - CALLBACK_NOTIFY(message_begin); - } else { - parser->type = HTTP_REQUEST; - parser->state = s_start_req; - goto reexecute_byte; - } - - break; - } - - case s_res_or_resp_H: - if (ch == 'T') { - parser->type = HTTP_RESPONSE; - parser->state = s_res_HT; - } else { - if (ch != 'E') { - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - - parser->type = HTTP_REQUEST; - parser->method = HTTP_HEAD; - parser->index = 2; - parser->state = s_req_method; - } - break; - - case s_start_res: - { - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - switch (ch) { - case 'H': - parser->state = s_res_H; - break; - - case CR: - case LF: - break; - - default: - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - - CALLBACK_NOTIFY(message_begin); - break; - } - - case s_res_H: - STRICT_CHECK(ch != 'T'); - parser->state = s_res_HT; - break; - - case s_res_HT: - STRICT_CHECK(ch != 'T'); - parser->state = s_res_HTT; - break; - - case s_res_HTT: - STRICT_CHECK(ch != 'P'); - parser->state = s_res_HTTP; - break; - - case s_res_HTTP: - STRICT_CHECK(ch != '/'); - parser->state = s_res_first_http_major; - break; - - case s_res_first_http_major: - if (ch < '0' || ch > '9') { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major = ch - '0'; - parser->state = s_res_http_major; - break; - - /* major HTTP version or dot */ - case s_res_http_major: - { - if (ch == '.') { - parser->state = s_res_first_http_minor; - break; - } - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major *= 10; - parser->http_major += ch - '0'; - - if (parser->http_major > 999) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* first digit of minor HTTP version */ - case s_res_first_http_minor: - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor = ch - '0'; - parser->state = s_res_http_minor; - break; - - /* minor HTTP version or end of request line */ - case s_res_http_minor: - { - if (ch == ' ') { - parser->state = s_res_first_status_code; - break; - } - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor *= 10; - parser->http_minor += ch - '0'; - - if (parser->http_minor > 999) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - case s_res_first_status_code: - { - if (!IS_NUM(ch)) { - if (ch == ' ') { - break; - } - - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - parser->status_code = ch - '0'; - parser->state = s_res_status_code; - break; - } - - case s_res_status_code: - { - if (!IS_NUM(ch)) { - switch (ch) { - case ' ': - parser->state = s_res_status; - break; - case CR: - parser->state = s_res_line_almost_done; - break; - case LF: - parser->state = s_header_field_start; - break; - default: - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - break; - } - - parser->status_code *= 10; - parser->status_code += ch - '0'; - - if (parser->status_code > 999) { - SET_ERRNO(HPE_INVALID_STATUS); - goto error; - } - - break; - } - - case s_res_status: - /* the human readable status. e.g. "NOT FOUND" - * we are not humans so just ignore this */ - if (ch == CR) { - parser->state = s_res_line_almost_done; - break; - } - - if (ch == LF) { - parser->state = s_header_field_start; - break; - } - break; - - case s_res_line_almost_done: - STRICT_CHECK(ch != LF); - parser->state = s_header_field_start; - CALLBACK_NOTIFY(status_complete); - break; - - case s_start_req: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = ULLONG_MAX; - - if (!IS_ALPHA(ch)) { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - parser->method = (enum http_method) 0; - parser->index = 1; - switch (ch) { - case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; - case 'D': parser->method = HTTP_DELETE; break; - case 'G': parser->method = HTTP_GET; break; - case 'H': parser->method = HTTP_HEAD; break; - case 'L': parser->method = HTTP_LOCK; break; - case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break; - case 'N': parser->method = HTTP_NOTIFY; break; - case 'O': parser->method = HTTP_OPTIONS; break; - case 'P': parser->method = HTTP_POST; - /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ - break; - case 'R': parser->method = HTTP_REPORT; break; - case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break; - case 'T': parser->method = HTTP_TRACE; break; - case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break; - default: - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - parser->state = s_req_method; - - CALLBACK_NOTIFY(message_begin); - - break; - } - - case s_req_method: - { - const char *matcher; - if (ch == '\0') { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - matcher = method_strings[parser->method]; - if (ch == ' ' && matcher[parser->index] == '\0') { - parser->state = s_req_spaces_before_url; - } else if (ch == matcher[parser->index]) { - ; /* nada */ - } else if (parser->method == HTTP_CONNECT) { - if (parser->index == 1 && ch == 'H') { - parser->method = HTTP_CHECKOUT; - } else if (parser->index == 2 && ch == 'P') { - parser->method = HTTP_COPY; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->method == HTTP_MKCOL) { - if (parser->index == 1 && ch == 'O') { - parser->method = HTTP_MOVE; - } else if (parser->index == 1 && ch == 'E') { - parser->method = HTTP_MERGE; - } else if (parser->index == 1 && ch == '-') { - parser->method = HTTP_MSEARCH; - } else if (parser->index == 2 && ch == 'A') { - parser->method = HTTP_MKACTIVITY; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->method == HTTP_SUBSCRIBE) { - if (parser->index == 1 && ch == 'E') { - parser->method = HTTP_SEARCH; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->index == 1 && parser->method == HTTP_POST) { - if (ch == 'R') { - parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ - } else if (ch == 'U') { - parser->method = HTTP_PUT; /* or HTTP_PURGE */ - } else if (ch == 'A') { - parser->method = HTTP_PATCH; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->index == 2) { - if (parser->method == HTTP_PUT) { - if (ch == 'R') { - parser->method = HTTP_PURGE; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->method == HTTP_UNLOCK) { - if (ch == 'S') { - parser->method = HTTP_UNSUBSCRIBE; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { - parser->method = HTTP_PROPPATCH; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - - ++parser->index; - break; - } - - case s_req_spaces_before_url: - { - if (ch == ' ') break; - - MARK(url); - if (parser->method == HTTP_CONNECT) { - parser->state = s_req_server_start; - } - - parser->state = parse_url_char((enum state)parser->state, ch); - if (parser->state == s_dead) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - - break; - } - - case s_req_schema: - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - { - switch (ch) { - /* No whitespace allowed here */ - case ' ': - case CR: - case LF: - SET_ERRNO(HPE_INVALID_URL); - goto error; - default: - parser->state = parse_url_char((enum state)parser->state, ch); - if (parser->state == s_dead) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - } - - break; - } - - case s_req_server: - case s_req_server_with_at: - case s_req_path: - case s_req_query_string_start: - case s_req_query_string: - case s_req_fragment_start: - case s_req_fragment: - { - switch (ch) { - case ' ': - parser->state = s_req_http_start; - CALLBACK_DATA(url); - break; - case CR: - case LF: - parser->http_major = 0; - parser->http_minor = 9; - parser->state = (ch == CR) ? - s_req_line_almost_done : - s_header_field_start; - CALLBACK_DATA(url); - break; - default: - parser->state = parse_url_char((enum state)parser->state, ch); - if (parser->state == s_dead) { - SET_ERRNO(HPE_INVALID_URL); - goto error; - } - } - break; - } - - case s_req_http_start: - switch (ch) { - case 'H': - parser->state = s_req_http_H; - break; - case ' ': - break; - default: - SET_ERRNO(HPE_INVALID_CONSTANT); - goto error; - } - break; - - case s_req_http_H: - STRICT_CHECK(ch != 'T'); - parser->state = s_req_http_HT; - break; - - case s_req_http_HT: - STRICT_CHECK(ch != 'T'); - parser->state = s_req_http_HTT; - break; - - case s_req_http_HTT: - STRICT_CHECK(ch != 'P'); - parser->state = s_req_http_HTTP; - break; - - case s_req_http_HTTP: - STRICT_CHECK(ch != '/'); - parser->state = s_req_first_http_major; - break; - - /* first digit of major HTTP version */ - case s_req_first_http_major: - if (ch < '1' || ch > '9') { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major = ch - '0'; - parser->state = s_req_http_major; - break; - - /* major HTTP version or dot */ - case s_req_http_major: - { - if (ch == '.') { - parser->state = s_req_first_http_minor; - break; - } - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_major *= 10; - parser->http_major += ch - '0'; - - if (parser->http_major > 999) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* first digit of minor HTTP version */ - case s_req_first_http_minor: - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor = ch - '0'; - parser->state = s_req_http_minor; - break; - - /* minor HTTP version or end of request line */ - case s_req_http_minor: - { - if (ch == CR) { - parser->state = s_req_line_almost_done; - break; - } - - if (ch == LF) { - parser->state = s_header_field_start; - break; - } - - /* XXX allow spaces after digit? */ - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - parser->http_minor *= 10; - parser->http_minor += ch - '0'; - - if (parser->http_minor > 999) { - SET_ERRNO(HPE_INVALID_VERSION); - goto error; - } - - break; - } - - /* end of request line */ - case s_req_line_almost_done: - { - if (ch != LF) { - SET_ERRNO(HPE_LF_EXPECTED); - goto error; - } - - parser->state = s_header_field_start; - break; - } - - case s_header_field_start: - { - if (ch == CR) { - parser->state = s_headers_almost_done; - break; - } - - if (ch == LF) { - /* they might be just sending \n instead of \r\n so this would be - * the second \n to denote the end of headers*/ - parser->state = s_headers_almost_done; - goto reexecute_byte; - } - - c = TOKEN(ch); - - if (!c) { - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - MARK(header_field); - - parser->index = 0; - parser->state = s_header_field; - - switch (c) { - case 'c': - parser->header_state = h_C; - break; - - case 'p': - parser->header_state = h_matching_proxy_connection; - break; - - case 't': - parser->header_state = h_matching_transfer_encoding; - break; - - case 'u': - parser->header_state = h_matching_upgrade; - break; - - default: - parser->header_state = h_general; - break; - } - break; - } - - case s_header_field: - { - c = TOKEN(ch); - - if (c) { - switch (parser->header_state) { - case h_general: - break; - - case h_C: - parser->index++; - parser->header_state = (c == 'o' ? h_CO : h_general); - break; - - case h_CO: - parser->index++; - parser->header_state = (c == 'n' ? h_CON : h_general); - break; - - case h_CON: - parser->index++; - switch (c) { - case 'n': - parser->header_state = h_matching_connection; - break; - case 't': - parser->header_state = h_matching_content_length; - break; - default: - parser->header_state = h_general; - break; - } - break; - - /* connection */ - - case h_matching_connection: - parser->index++; - if (parser->index > sizeof(CONNECTION)-1 - || c != CONNECTION[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CONNECTION)-2) { - parser->header_state = h_connection; - } - break; - - /* proxy-connection */ - - case h_matching_proxy_connection: - parser->index++; - if (parser->index > sizeof(PROXY_CONNECTION)-1 - || c != PROXY_CONNECTION[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(PROXY_CONNECTION)-2) { - parser->header_state = h_connection; - } - break; - - /* content-length */ - - case h_matching_content_length: - parser->index++; - if (parser->index > sizeof(CONTENT_LENGTH)-1 - || c != CONTENT_LENGTH[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CONTENT_LENGTH)-2) { - parser->header_state = h_content_length; - } - break; - - /* transfer-encoding */ - - case h_matching_transfer_encoding: - parser->index++; - if (parser->index > sizeof(TRANSFER_ENCODING)-1 - || c != TRANSFER_ENCODING[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(TRANSFER_ENCODING)-2) { - parser->header_state = h_transfer_encoding; - } - break; - - /* upgrade */ - - case h_matching_upgrade: - parser->index++; - if (parser->index > sizeof(UPGRADE)-1 - || c != UPGRADE[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(UPGRADE)-2) { - parser->header_state = h_upgrade; - } - break; - - case h_connection: - case h_content_length: - case h_transfer_encoding: - case h_upgrade: - if (ch != ' ') parser->header_state = h_general; - break; - - default: - assert(0 && "Unknown header_state"); - break; - } - break; - } - - if (ch == ':') { - parser->state = s_header_value_start; - CALLBACK_DATA(header_field); - break; - } - - if (ch == CR) { - parser->state = s_header_almost_done; - CALLBACK_DATA(header_field); - break; - } - - if (ch == LF) { - parser->state = s_header_field_start; - CALLBACK_DATA(header_field); - break; - } - - SET_ERRNO(HPE_INVALID_HEADER_TOKEN); - goto error; - } - - case s_header_value_start: - { - if (ch == ' ' || ch == '\t') break; - - MARK(header_value); - - parser->state = s_header_value; - parser->index = 0; - - if (ch == CR) { - parser->header_state = h_general; - parser->state = s_header_almost_done; - CALLBACK_DATA(header_value); - break; - } - - if (ch == LF) { - parser->state = s_header_field_start; - CALLBACK_DATA(header_value); - break; - } - - c = LOWER(ch); - - switch (parser->header_state) { - case h_upgrade: - parser->flags |= F_UPGRADE; - parser->header_state = h_general; - break; - - case h_transfer_encoding: - /* looking for 'Transfer-Encoding: chunked' */ - if ('c' == c) { - parser->header_state = h_matching_transfer_encoding_chunked; - } else { - parser->header_state = h_general; - } - break; - - case h_content_length: - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - parser->content_length = ch - '0'; - break; - - case h_connection: - /* looking for 'Connection: keep-alive' */ - if (c == 'k') { - parser->header_state = h_matching_connection_keep_alive; - /* looking for 'Connection: close' */ - } else if (c == 'c') { - parser->header_state = h_matching_connection_close; - } else { - parser->header_state = h_general; - } - break; - - default: - parser->header_state = h_general; - break; - } - break; - } - - case s_header_value: - { - - if (ch == CR) { - parser->state = s_header_almost_done; - CALLBACK_DATA(header_value); - break; - } - - if (ch == LF) { - parser->state = s_header_almost_done; - CALLBACK_DATA_NOADVANCE(header_value); - goto reexecute_byte; - } - - c = LOWER(ch); - - switch (parser->header_state) { - case h_general: - break; - - case h_connection: - case h_transfer_encoding: - assert(0 && "Shouldn't get here."); - break; - - case h_content_length: - { - uint64_t t; - - if (ch == ' ') break; - - if (!IS_NUM(ch)) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - t = parser->content_length; - t *= 10; - t += ch - '0'; - - /* Overflow? */ - if (t < parser->content_length || t == ULLONG_MAX) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - parser->content_length = t; - break; - } - - /* Transfer-Encoding: chunked */ - case h_matching_transfer_encoding_chunked: - parser->index++; - if (parser->index > sizeof(CHUNKED)-1 - || c != CHUNKED[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CHUNKED)-2) { - parser->header_state = h_transfer_encoding_chunked; - } - break; - - /* looking for 'Connection: keep-alive' */ - case h_matching_connection_keep_alive: - parser->index++; - if (parser->index > sizeof(KEEP_ALIVE)-1 - || c != KEEP_ALIVE[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(KEEP_ALIVE)-2) { - parser->header_state = h_connection_keep_alive; - } - break; - - /* looking for 'Connection: close' */ - case h_matching_connection_close: - parser->index++; - if (parser->index > sizeof(CLOSE)-1 || c != CLOSE[parser->index]) { - parser->header_state = h_general; - } else if (parser->index == sizeof(CLOSE)-2) { - parser->header_state = h_connection_close; - } - break; - - case h_transfer_encoding_chunked: - case h_connection_keep_alive: - case h_connection_close: - if (ch != ' ') parser->header_state = h_general; - break; - - default: - parser->state = s_header_value; - parser->header_state = h_general; - break; - } - break; - } - - case s_header_almost_done: - { - STRICT_CHECK(ch != LF); - - parser->state = s_header_value_lws; - - switch (parser->header_state) { - case h_connection_keep_alive: - parser->flags |= F_CONNECTION_KEEP_ALIVE; - break; - case h_connection_close: - parser->flags |= F_CONNECTION_CLOSE; - break; - case h_transfer_encoding_chunked: - parser->flags |= F_CHUNKED; - break; - default: - break; - } - - break; - } - - case s_header_value_lws: - { - if (ch == ' ' || ch == '\t') - parser->state = s_header_value_start; - else - { - parser->state = s_header_field_start; - goto reexecute_byte; - } - break; - } - - case s_headers_almost_done: - { - STRICT_CHECK(ch != LF); - - if (parser->flags & F_TRAILING) { - /* End of a chunked request */ - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - break; - } - - parser->state = s_headers_done; - - /* Set this here so that on_headers_complete() callbacks can see it */ - parser->upgrade = - (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT); - - /* Here we call the headers_complete callback. This is somewhat - * different than other callbacks because if the user returns 1, we - * will interpret that as saying that this message has no body. This - * is needed for the annoying case of recieving a response to a HEAD - * request. - * - * We'd like to use CALLBACK_NOTIFY_NOADVANCE() here but we cannot, so - * we have to simulate it by handling a change in errno below. - */ - if (settings->on_headers_complete) { - switch (settings->on_headers_complete(parser)) { - case 0: - break; - - case 1: - parser->flags |= F_SKIPBODY; - break; - - default: - SET_ERRNO(HPE_CB_headers_complete); - return p - data; /* Error */ - } - } - - if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { - return p - data; - } - - goto reexecute_byte; - } - - case s_headers_done: - { - STRICT_CHECK(ch != LF); - - parser->nread = 0; - - /* Exit, the rest of the connect is in a different protocol. */ - if (parser->upgrade) { - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - return (p - data) + 1; - } - - if (parser->flags & F_SKIPBODY) { - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - } else if (parser->flags & F_CHUNKED) { - /* chunked encoding - ignore Content-Length header */ - parser->state = s_chunk_size_start; - } else { - if (parser->content_length == 0) { - /* Content-Length header given but zero: Content-Length: 0\r\n */ - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - } else if (parser->content_length != ULLONG_MAX) { - /* Content-Length header given and non-zero */ - parser->state = s_body_identity; - } else { - if (parser->type == HTTP_REQUEST || - !http_message_needs_eof(parser)) { - /* Assume content-length 0 - read the next */ - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - } else { - /* Read body until EOF */ - parser->state = s_body_identity_eof; - } - } - } - - break; - } - - case s_body_identity: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t) ((data + len) - p)); - - assert(parser->content_length != 0 - && parser->content_length != ULLONG_MAX); - - /* The difference between advancing content_length and p is because - * the latter will automaticaly advance on the next loop iteration. - * Further, if content_length ends up at 0, we want to see the last - * byte again for our message complete callback. - */ - MARK(body); - parser->content_length -= to_read; - p += to_read - 1; - - if (parser->content_length == 0) { - parser->state = s_message_done; - - /* Mimic CALLBACK_DATA_NOADVANCE() but with one extra byte. - * - * The alternative to doing this is to wait for the next byte to - * trigger the data callback, just as in every other case. The - * problem with this is that this makes it difficult for the test - * harness to distinguish between complete-on-EOF and - * complete-on-length. It's not clear that this distinction is - * important for applications, but let's keep it for now. - */ - CALLBACK_DATA_(body, p - body_mark + 1, p - data); - goto reexecute_byte; - } - - break; - } - - /* read until EOF */ - case s_body_identity_eof: - MARK(body); - p = data + len - 1; - - break; - - case s_message_done: - parser->state = NEW_MESSAGE(); - CALLBACK_NOTIFY(message_complete); - break; - - case s_chunk_size_start: - { - assert(parser->nread == 1); - assert(parser->flags & F_CHUNKED); - - unhex_val = unhex[(unsigned char)ch]; - if (unhex_val == -1) { - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); - goto error; - } - - parser->content_length = unhex_val; - parser->state = s_chunk_size; - break; - } - - case s_chunk_size: - { - uint64_t t; - - assert(parser->flags & F_CHUNKED); - - if (ch == CR) { - parser->state = s_chunk_size_almost_done; - break; - } - - unhex_val = unhex[(unsigned char)ch]; - - if (unhex_val == -1) { - if (ch == ';' || ch == ' ') { - parser->state = s_chunk_parameters; - break; - } - - SET_ERRNO(HPE_INVALID_CHUNK_SIZE); - goto error; - } - - t = parser->content_length; - t *= 16; - t += unhex_val; - - /* Overflow? */ - if (t < parser->content_length || t == ULLONG_MAX) { - SET_ERRNO(HPE_INVALID_CONTENT_LENGTH); - goto error; - } - - parser->content_length = t; - break; - } - - case s_chunk_parameters: - { - assert(parser->flags & F_CHUNKED); - /* just ignore this shit. TODO check for overflow */ - if (ch == CR) { - parser->state = s_chunk_size_almost_done; - break; - } - break; - } - - case s_chunk_size_almost_done: - { - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - - parser->nread = 0; - - if (parser->content_length == 0) { - parser->flags |= F_TRAILING; - parser->state = s_header_field_start; - } else { - parser->state = s_chunk_data; - } - break; - } - - case s_chunk_data: - { - uint64_t to_read = MIN(parser->content_length, - (uint64_t) ((data + len) - p)); - - assert(parser->flags & F_CHUNKED); - assert(parser->content_length != 0 - && parser->content_length != ULLONG_MAX); - - /* See the explanation in s_body_identity for why the content - * length and data pointers are managed this way. - */ - MARK(body); - parser->content_length -= to_read; - p += to_read - 1; - - if (parser->content_length == 0) { - parser->state = s_chunk_data_almost_done; - } - - break; - } - - case s_chunk_data_almost_done: - assert(parser->flags & F_CHUNKED); - assert(parser->content_length == 0); - STRICT_CHECK(ch != CR); - parser->state = s_chunk_data_done; - CALLBACK_DATA(body); - break; - - case s_chunk_data_done: - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - parser->nread = 0; - parser->state = s_chunk_size_start; - break; - - default: - assert(0 && "unhandled state"); - SET_ERRNO(HPE_INVALID_INTERNAL_STATE); - goto error; - } - } - - /* Run callbacks for any marks that we have leftover after we ran our of - * bytes. There should be at most one of these set, so it's OK to invoke - * them in series (unset marks will not result in callbacks). - * - * We use the NOADVANCE() variety of callbacks here because 'p' has already - * overflowed 'data' and this allows us to correct for the off-by-one that - * we'd otherwise have (since CALLBACK_DATA() is meant to be run with a 'p' - * value that's in-bounds). - */ - - assert(((header_field_mark ? 1 : 0) + - (header_value_mark ? 1 : 0) + - (url_mark ? 1 : 0) + - (body_mark ? 1 : 0)) <= 1); - - CALLBACK_DATA_NOADVANCE(header_field); - CALLBACK_DATA_NOADVANCE(header_value); - CALLBACK_DATA_NOADVANCE(url); - CALLBACK_DATA_NOADVANCE(body); - - return len; - -error: - if (HTTP_PARSER_ERRNO(parser) == HPE_OK) { - SET_ERRNO(HPE_UNKNOWN); - } - - return (p - data); -} - - -/* Does the parser need to see an EOF to find the end of the message? */ -int -http_message_needs_eof (const http_parser *parser) -{ - if (parser->type == HTTP_REQUEST) { - return 0; - } - - /* See RFC 2616 section 4.4 */ - if (parser->status_code / 100 == 1 || /* 1xx e.g. Continue */ - parser->status_code == 204 || /* No Content */ - parser->status_code == 304 || /* Not Modified */ - parser->flags & F_SKIPBODY) { /* response to a HEAD request */ - return 0; - } - - if ((parser->flags & F_CHUNKED) || parser->content_length != ULLONG_MAX) { - return 0; - } - - return 1; -} - - -int -http_should_keep_alive (const http_parser *parser) -{ - if (parser->http_major > 0 && parser->http_minor > 0) { - /* HTTP/1.1 */ - if (parser->flags & F_CONNECTION_CLOSE) { - return 0; - } - } else { - /* HTTP/1.0 or earlier */ - if (!(parser->flags & F_CONNECTION_KEEP_ALIVE)) { - return 0; - } - } - - return !http_message_needs_eof(parser); -} - - -const char * -http_method_str (enum http_method m) -{ - return ELEM_AT(method_strings, m, ""); -} - - -void -http_parser_init (http_parser *parser, enum http_parser_type t) -{ - void *data = parser->data; /* preserve application data */ - memset(parser, 0, sizeof(*parser)); - parser->data = data; - parser->type = t; - parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); - parser->http_errno = HPE_OK; -} - -const char * -http_errno_name(enum http_errno err) { - assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); - return http_strerror_tab[err].name; -} - -const char * -http_errno_description(enum http_errno err) { - assert(err < (sizeof(http_strerror_tab)/sizeof(http_strerror_tab[0]))); - return http_strerror_tab[err].description; -} - -static enum http_host_state -http_parse_host_char(enum http_host_state s, const char ch) { - switch(s) { - case s_http_userinfo: - case s_http_userinfo_start: - if (ch == '@') { - return s_http_host_start; - } - - if (IS_USERINFO_CHAR(ch)) { - return s_http_userinfo; - } - break; - - case s_http_host_start: - if (ch == '[') { - return s_http_host_v6_start; - } - - if (IS_HOST_CHAR(ch)) { - return s_http_host; - } - - break; - - case s_http_host: - if (IS_HOST_CHAR(ch)) { - return s_http_host; - } - - /* FALLTHROUGH */ - case s_http_host_v6_end: - if (ch == ':') { - return s_http_host_port_start; - } - - break; - - case s_http_host_v6: - if (ch == ']') { - return s_http_host_v6_end; - } - - /* FALLTHROUGH */ - case s_http_host_v6_start: - if (IS_HEX(ch) || ch == ':' || ch == '.') { - return s_http_host_v6; - } - - break; - - case s_http_host_port: - case s_http_host_port_start: - if (IS_NUM(ch)) { - return s_http_host_port; - } - - break; - - default: - break; - } - return s_http_host_dead; -} - -static int -http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { - enum http_host_state s; - - const char *p; - size_t buflen = u->field_data[UF_HOST].off + u->field_data[UF_HOST].len; - - u->field_data[UF_HOST].len = 0; - - s = found_at ? s_http_userinfo_start : s_http_host_start; - - for (p = buf + u->field_data[UF_HOST].off; p < buf + buflen; p++) { - enum http_host_state new_s = http_parse_host_char(s, *p); - - if (new_s == s_http_host_dead) { - return 1; - } - - switch(new_s) { - case s_http_host: - if (s != s_http_host) { - u->field_data[UF_HOST].off = p - buf; - } - u->field_data[UF_HOST].len++; - break; - - case s_http_host_v6: - if (s != s_http_host_v6) { - u->field_data[UF_HOST].off = p - buf; - } - u->field_data[UF_HOST].len++; - break; - - case s_http_host_port: - if (s != s_http_host_port) { - u->field_data[UF_PORT].off = p - buf; - u->field_data[UF_PORT].len = 0; - u->field_set |= (1 << UF_PORT); - } - u->field_data[UF_PORT].len++; - break; - - case s_http_userinfo: - if (s != s_http_userinfo) { - u->field_data[UF_USERINFO].off = p - buf ; - u->field_data[UF_USERINFO].len = 0; - u->field_set |= (1 << UF_USERINFO); - } - u->field_data[UF_USERINFO].len++; - break; - - default: - break; - } - s = new_s; - } - - /* Make sure we don't end somewhere unexpected */ - switch (s) { - case s_http_host_start: - case s_http_host_v6_start: - case s_http_host_v6: - case s_http_host_port_start: - case s_http_userinfo: - case s_http_userinfo_start: - return 1; - default: - break; - } - - return 0; -} - -int -http_parser_parse_url(const char *buf, size_t buflen, int is_connect, - struct http_parser_url *u) -{ - enum state s; - const char *p; - enum http_parser_url_fields uf, old_uf; - int found_at = 0; - - u->port = u->field_set = 0; - s = is_connect ? s_req_server_start : s_req_spaces_before_url; - uf = old_uf = UF_MAX; - - for (p = buf; p < buf + buflen; p++) { - s = parse_url_char(s, *p); - - /* Figure out the next field that we're operating on */ - switch (s) { - case s_dead: - return 1; - - /* Skip delimeters */ - case s_req_schema_slash: - case s_req_schema_slash_slash: - case s_req_server_start: - case s_req_query_string_start: - case s_req_fragment_start: - continue; - - case s_req_schema: - uf = UF_SCHEMA; - break; - - case s_req_server_with_at: - found_at = 1; - - /* FALLTROUGH */ - case s_req_server: - uf = UF_HOST; - break; - - case s_req_path: - uf = UF_PATH; - break; - - case s_req_query_string: - uf = UF_QUERY; - break; - - case s_req_fragment: - uf = UF_FRAGMENT; - break; - - default: - assert(!"Unexpected state"); - return 1; - } - - /* Nothing's changed; soldier on */ - if (uf == old_uf) { - u->field_data[uf].len++; - continue; - } - - u->field_data[uf].off = p - buf; - u->field_data[uf].len = 1; - - u->field_set |= (1 << uf); - old_uf = uf; - } - - /* host must be present if there is a schema */ - /* parsing http:///toto will fail */ - if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) { - if (http_parse_host(buf, u, found_at) != 0) { - return 1; - } - } - - /* CONNECT requests can only contain "hostname:port" */ - if (is_connect && u->field_set != ((1 << UF_HOST)|(1 << UF_PORT))) { - return 1; - } - - if (u->field_set & (1 << UF_PORT)) { - /* Don't bother with endp; we've already validated the string */ - unsigned long v = strtoul(buf + u->field_data[UF_PORT].off, NULL, 10); - - /* Ports have a max value of 2^16 */ - if (v > 0xffff) { - return 1; - } - - u->port = (uint16_t) v; - } - - return 0; -} - -void -http_parser_pause(http_parser *parser, int paused) { - /* Users should only be pausing/unpausing a parser that is not in an error - * state. In non-debug builds, there's not much that we can do about this - * other than ignore it. - */ - if (HTTP_PARSER_ERRNO(parser) == HPE_OK || - HTTP_PARSER_ERRNO(parser) == HPE_PAUSED) { - SET_ERRNO((paused) ? HPE_PAUSED : HPE_OK); - } else { - assert(0 && "Attempting to pause parser in error state"); - } -} - -int -http_body_is_final(const struct http_parser *parser) { - return parser->state == s_message_done; -} - -unsigned long -http_parser_version(void) { - return HTTP_PARSER_VERSION_MAJOR * 0x10000 | - HTTP_PARSER_VERSION_MINOR * 0x00100 | - HTTP_PARSER_VERSION_PATCH * 0x00001; -} diff --git a/src/beast/modules/beast_asio/parsehttp/http_parser.gyp b/src/beast/modules/beast_asio/parsehttp/http_parser.gyp deleted file mode 100644 index ef34ecaeae..0000000000 --- a/src/beast/modules/beast_asio/parsehttp/http_parser.gyp +++ /dev/null @@ -1,111 +0,0 @@ -# This file is used with the GYP meta build system. -# http://code.google.com/p/gyp/ -# To build try this: -# svn co http://gyp.googlecode.com/svn/trunk gyp -# ./gyp/gyp -f make --depth=`pwd` http_parser.gyp -# ./out/Debug/test -{ - 'target_defaults': { - 'default_configuration': 'Debug', - 'configurations': { - # TODO: hoist these out and put them somewhere common, because - # RuntimeLibrary MUST MATCH across the entire project - 'Debug': { - 'defines': [ 'DEBUG', '_DEBUG' ], - 'cflags': [ '-Wall', '-Wextra', '-O0', '-g', '-ftrapv' ], - 'msvs_settings': { - 'VCCLCompilerTool': { - 'RuntimeLibrary': 1, # static debug - }, - }, - }, - 'Release': { - 'defines': [ 'NDEBUG' ], - 'cflags': [ '-Wall', '-Wextra', '-O3' ], - 'msvs_settings': { - 'VCCLCompilerTool': { - 'RuntimeLibrary': 0, # static release - }, - }, - } - }, - 'msvs_settings': { - 'VCCLCompilerTool': { - }, - 'VCLibrarianTool': { - }, - 'VCLinkerTool': { - 'GenerateDebugInformation': 'true', - }, - }, - 'conditions': [ - ['OS == "win"', { - 'defines': [ - 'WIN32' - ], - }] - ], - }, - - 'targets': [ - { - 'target_name': 'http_parser', - 'type': 'static_library', - 'include_dirs': [ '.' ], - 'direct_dependent_settings': { - 'defines': [ 'HTTP_PARSER_STRICT=0' ], - 'include_dirs': [ '.' ], - }, - 'defines': [ 'HTTP_PARSER_STRICT=0' ], - 'sources': [ './http_parser.c', ], - 'conditions': [ - ['OS=="win"', { - 'msvs_settings': { - 'VCCLCompilerTool': { - # Compile as C++. http_parser.c is actually C99, but C++ is - # close enough in this case. - 'CompileAs': 2, - }, - }, - }] - ], - }, - - { - 'target_name': 'http_parser_strict', - 'type': 'static_library', - 'include_dirs': [ '.' ], - 'direct_dependent_settings': { - 'defines': [ 'HTTP_PARSER_STRICT=1' ], - 'include_dirs': [ '.' ], - }, - 'defines': [ 'HTTP_PARSER_STRICT=1' ], - 'sources': [ './http_parser.c', ], - 'conditions': [ - ['OS=="win"', { - 'msvs_settings': { - 'VCCLCompilerTool': { - # Compile as C++. http_parser.c is actually C99, but C++ is - # close enough in this case. - 'CompileAs': 2, - }, - }, - }] - ], - }, - - { - 'target_name': 'test-nonstrict', - 'type': 'executable', - 'dependencies': [ 'http_parser' ], - 'sources': [ 'test.c' ] - }, - - { - 'target_name': 'test-strict', - 'type': 'executable', - 'dependencies': [ 'http_parser_strict' ], - 'sources': [ 'test.c' ] - } - ] -} diff --git a/src/beast/modules/beast_asio/parsehttp/http_parser.h b/src/beast/modules/beast_asio/parsehttp/http_parser.h deleted file mode 100644 index 98c0905b2d..0000000000 --- a/src/beast/modules/beast_asio/parsehttp/http_parser.h +++ /dev/null @@ -1,318 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#ifndef http_parser_h -#define http_parser_h -#ifdef __cplusplus -extern "C" { -#endif - -/* Also update SONAME in the Makefile whenever you change these. */ -#define HTTP_PARSER_VERSION_MAJOR 2 -#define HTTP_PARSER_VERSION_MINOR 1 -#define HTTP_PARSER_VERSION_PATCH 0 - -#include -#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) -#include -#include -typedef __int8 int8_t; -typedef unsigned __int8 uint8_t; -typedef __int16 int16_t; -typedef unsigned __int16 uint16_t; -typedef __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -#include -#endif - -/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run - * faster - */ -#ifndef HTTP_PARSER_STRICT -# define HTTP_PARSER_STRICT 1 -#endif - -/* Maximium header size allowed */ -#define HTTP_MAX_HEADER_SIZE (80*1024) - - -typedef struct http_parser http_parser; -typedef struct http_parser_settings http_parser_settings; - - -/* Callbacks should return non-zero to indicate an error. The parser will - * then halt execution. - * - * The one exception is on_headers_complete. In a HTTP_RESPONSE parser - * returning '1' from on_headers_complete will tell the parser that it - * should not expect a body. This is used when receiving a response to a - * HEAD request which may contain 'Content-Length' or 'Transfer-Encoding: - * chunked' headers that indicate the presence of a body. - * - * http_data_cb does not return data chunks. It will be call arbitrarally - * many times for each string. E.G. you might get 10 callbacks for "on_url" - * each providing just a few characters more data. - */ -typedef int (*http_data_cb) (http_parser*, const char *at, size_t length); -typedef int (*http_cb) (http_parser*); - - -/* Request Methods */ -#define HTTP_METHOD_MAP(XX) \ - XX(0, DELETE, DELETE) \ - XX(1, GET, GET) \ - XX(2, HEAD, HEAD) \ - XX(3, POST, POST) \ - XX(4, PUT, PUT) \ - /* pathological */ \ - XX(5, CONNECT, CONNECT) \ - XX(6, OPTIONS, OPTIONS) \ - XX(7, TRACE, TRACE) \ - /* webdav */ \ - XX(8, COPY, COPY) \ - XX(9, LOCK, LOCK) \ - XX(10, MKCOL, MKCOL) \ - XX(11, MOVE, MOVE) \ - XX(12, PROPFIND, PROPFIND) \ - XX(13, PROPPATCH, PROPPATCH) \ - XX(14, SEARCH, SEARCH) \ - XX(15, UNLOCK, UNLOCK) \ - /* subversion */ \ - XX(16, REPORT, REPORT) \ - XX(17, MKACTIVITY, MKACTIVITY) \ - XX(18, CHECKOUT, CHECKOUT) \ - XX(19, MERGE, MERGE) \ - /* upnp */ \ - XX(20, MSEARCH, M-SEARCH) \ - XX(21, NOTIFY, NOTIFY) \ - XX(22, SUBSCRIBE, SUBSCRIBE) \ - XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \ - /* RFC-5789 */ \ - XX(24, PATCH, PATCH) \ - XX(25, PURGE, PURGE) \ - -enum http_method - { -#define XX(num, name, string) HTTP_##name = num, - HTTP_METHOD_MAP(XX) -#undef XX - }; - - -enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH }; - - -/* Flag values for http_parser.flags field */ -enum flags - { F_CHUNKED = 1 << 0 - , F_CONNECTION_KEEP_ALIVE = 1 << 1 - , F_CONNECTION_CLOSE = 1 << 2 - , F_TRAILING = 1 << 3 - , F_UPGRADE = 1 << 4 - , F_SKIPBODY = 1 << 5 - }; - - -/* Map for errno-related constants - * - * The provided argument should be a macro that takes 2 arguments. - */ -#define HTTP_ERRNO_MAP(XX) \ - /* No error */ \ - XX(OK, "success") \ - \ - /* Callback-related errors */ \ - XX(CB_message_begin, "the on_message_begin callback failed") \ - XX(CB_status_complete, "the on_status_complete callback failed") \ - XX(CB_url, "the on_url callback failed") \ - XX(CB_header_field, "the on_header_field callback failed") \ - XX(CB_header_value, "the on_header_value callback failed") \ - XX(CB_headers_complete, "the on_headers_complete callback failed") \ - XX(CB_body, "the on_body callback failed") \ - XX(CB_message_complete, "the on_message_complete callback failed") \ - \ - /* Parsing-related errors */ \ - XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \ - XX(HEADER_OVERFLOW, \ - "too many header bytes seen; overflow detected") \ - XX(CLOSED_CONNECTION, \ - "data received after completed connection: close message") \ - XX(INVALID_VERSION, "invalid HTTP version") \ - XX(INVALID_STATUS, "invalid HTTP status code") \ - XX(INVALID_METHOD, "invalid HTTP method") \ - XX(INVALID_URL, "invalid URL") \ - XX(INVALID_HOST, "invalid host") \ - XX(INVALID_PORT, "invalid port") \ - XX(INVALID_PATH, "invalid path") \ - XX(INVALID_QUERY_STRING, "invalid query string") \ - XX(INVALID_FRAGMENT, "invalid fragment") \ - XX(LF_EXPECTED, "LF character expected") \ - XX(INVALID_HEADER_TOKEN, "invalid character in header") \ - XX(INVALID_CONTENT_LENGTH, \ - "invalid character in content-length header") \ - XX(INVALID_CHUNK_SIZE, \ - "invalid character in chunk size header") \ - XX(INVALID_CONSTANT, "invalid constant string") \ - XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\ - XX(STRICT, "strict mode assertion failed") \ - XX(PAUSED, "parser is paused") \ - XX(UNKNOWN, "an unknown error occurred") - - -/* Define HPE_* values for each errno value above */ -#define HTTP_ERRNO_GEN(n, s) HPE_##n, -enum http_errno { - HTTP_ERRNO_MAP(HTTP_ERRNO_GEN) -}; -#undef HTTP_ERRNO_GEN - - -/* Get an http_errno value from an http_parser */ -#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno) - - -struct http_parser { - /** PRIVATE **/ - unsigned char type : 2; /* enum http_parser_type */ - unsigned char flags : 6; /* F_* values from 'flags' enum; semi-public */ - unsigned char state; /* enum state from http_parser.c */ - unsigned char header_state; /* enum header_state from http_parser.c */ - unsigned char index; /* index into current matcher */ - - uint32_t nread; /* # bytes read in various scenarios */ - uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ - - /** READ-ONLY **/ - unsigned short http_major; - unsigned short http_minor; - unsigned short status_code; /* responses only */ - unsigned char method; /* requests only */ - unsigned char http_errno : 7; - - /* 1 = Upgrade header was present and the parser has exited because of that. - * 0 = No upgrade header present. - * Should be checked when http_parser_execute() returns in addition to - * error checking. - */ - unsigned char upgrade : 1; - - /** PUBLIC **/ - void *data; /* A pointer to get hook to the "connection" or "socket" object */ -}; - - -struct http_parser_settings { - http_cb on_message_begin; - http_data_cb on_url; - http_cb on_status_complete; - http_data_cb on_header_field; - http_data_cb on_header_value; - http_cb on_headers_complete; - http_data_cb on_body; - http_cb on_message_complete; -}; - - -enum http_parser_url_fields - { UF_SCHEMA = 0 - , UF_HOST = 1 - , UF_PORT = 2 - , UF_PATH = 3 - , UF_QUERY = 4 - , UF_FRAGMENT = 5 - , UF_USERINFO = 6 - , UF_MAX = 7 - }; - - -/* Result structure for http_parser_parse_url(). - * - * Callers should index into field_data[] with UF_* values iff field_set - * has the relevant (1 << UF_*) bit set. As a courtesy to clients (and - * because we probably have padding left over), we convert any port to - * a uint16_t. - */ -struct http_parser_url { - uint16_t field_set; /* Bitmask of (1 << UF_*) values */ - uint16_t port; /* Converted UF_PORT string */ - - struct { - uint16_t off; /* Offset into buffer in which field starts */ - uint16_t len; /* Length of run in buffer */ - } field_data[UF_MAX]; -}; - - -/* Returns the library version. Bits 16-23 contain the major version number, - * bits 8-15 the minor version number and bits 0-7 the patch level. - * Usage example: - * - * unsigned long version = http_parser_version(); - * unsigned major = (version >> 16) & 255; - * unsigned minor = (version >> 8) & 255; - * unsigned patch = version & 255; - * printf("http_parser v%u.%u.%u\n", major, minor, version); - */ -unsigned long http_parser_version(void); - -void http_parser_init(http_parser *parser, enum http_parser_type type); - - -size_t http_parser_execute(http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len); - - -/* If http_should_keep_alive() in the on_headers_complete or - * on_message_complete callback returns 0, then this should be - * the last message on the connection. - * If you are the server, respond with the "Connection: close" header. - * If you are the client, close the connection. - */ -int http_should_keep_alive(const http_parser *parser); - -/* Returns a string version of the HTTP method. */ -const char *http_method_str(enum http_method m); - -/* Return a string name of the given error */ -const char *http_errno_name(enum http_errno err); - -/* Return a string description of the given error */ -const char *http_errno_description(enum http_errno err); - -/* Parse a URL; return nonzero on failure */ -int http_parser_parse_url(const char *buf, size_t buflen, - int is_connect, - struct http_parser_url *u); - -/* Pause or un-pause the parser; a nonzero value pauses */ -void http_parser_pause(http_parser *parser, int paused); - -/* Checks if this is the final chunk of the body. */ -int http_body_is_final(const http_parser *parser); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/beast/modules/beast_asio/parsehttp/test.c b/src/beast/modules/beast_asio/parsehttp/test.c deleted file mode 100644 index b9a5ac3861..0000000000 --- a/src/beast/modules/beast_asio/parsehttp/test.c +++ /dev/null @@ -1,3439 +0,0 @@ -/* Copyright Joyent, Inc. and other Node contributors. All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - * IN THE SOFTWARE. - */ -#include "http_parser.h" -#include -#include -#include -#include /* rand */ -#include -#include - -#undef TRUE -#define TRUE 1 -#undef FALSE -#define FALSE 0 - -#define MAX_HEADERS 13 -#define MAX_ELEMENT_SIZE 2048 - -#define MIN(a,b) ((a) < (b) ? (a) : (b)) - -static http_parser *parser; - -struct message { - const char *name; // for debugging purposes - const char *raw; - enum http_parser_type type; - enum http_method method; - int status_code; - char request_path[MAX_ELEMENT_SIZE]; - char request_url[MAX_ELEMENT_SIZE]; - char fragment[MAX_ELEMENT_SIZE]; - char query_string[MAX_ELEMENT_SIZE]; - char body[MAX_ELEMENT_SIZE]; - size_t body_size; - const char *host; - const char *userinfo; - uint16_t port; - int num_headers; - enum { NONE=0, FIELD, VALUE } last_header_element; - char headers [MAX_HEADERS][2][MAX_ELEMENT_SIZE]; - int should_keep_alive; - - const char *upgrade; // upgraded body - - unsigned short http_major; - unsigned short http_minor; - - int message_begin_cb_called; - int headers_complete_cb_called; - int message_complete_cb_called; - int message_complete_on_eof; - int body_is_final; -}; - -static int currently_parsing_eof; - -static struct message messages[5]; -static int num_messages; -static http_parser_settings *current_pause_parser; - -/* * R E Q U E S T S * */ -const struct message requests[] = -#define CURL_GET 0 -{ {.name= "curl get" - ,.type= HTTP_REQUEST - ,.raw= "GET /test HTTP/1.1\r\n" - "User-Agent: curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1\r\n" - "Host: 0.0.0.0=5000\r\n" - "Accept: */*\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_GET - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/test" - ,.request_url= "/test" - ,.num_headers= 3 - ,.headers= - { { "User-Agent", "curl/7.18.0 (i486-pc-linux-gnu) libcurl/7.18.0 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.1" } - , { "Host", "0.0.0.0=5000" } - , { "Accept", "*/*" } - } - ,.body= "" - } - -#define FIREFOX_GET 1 -, {.name= "firefox get" - ,.type= HTTP_REQUEST - ,.raw= "GET /favicon.ico HTTP/1.1\r\n" - "Host: 0.0.0.0=5000\r\n" - "User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0\r\n" - "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" - "Accept-Language: en-us,en;q=0.5\r\n" - "Accept-Encoding: gzip,deflate\r\n" - "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" - "Keep-Alive: 300\r\n" - "Connection: keep-alive\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_GET - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/favicon.ico" - ,.request_url= "/favicon.ico" - ,.num_headers= 8 - ,.headers= - { { "Host", "0.0.0.0=5000" } - , { "User-Agent", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9) Gecko/2008061015 Firefox/3.0" } - , { "Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" } - , { "Accept-Language", "en-us,en;q=0.5" } - , { "Accept-Encoding", "gzip,deflate" } - , { "Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7" } - , { "Keep-Alive", "300" } - , { "Connection", "keep-alive" } - } - ,.body= "" - } - -#define DUMBFUCK 2 -, {.name= "dumbfuck" - ,.type= HTTP_REQUEST - ,.raw= "GET /dumbfuck HTTP/1.1\r\n" - "aaaaaaaaaaaaa:++++++++++\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_GET - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/dumbfuck" - ,.request_url= "/dumbfuck" - ,.num_headers= 1 - ,.headers= - { { "aaaaaaaaaaaaa", "++++++++++" } - } - ,.body= "" - } - -#define FRAGMENT_IN_URI 3 -, {.name= "fragment in url" - ,.type= HTTP_REQUEST - ,.raw= "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_GET - ,.query_string= "page=1" - ,.fragment= "posts-17408" - ,.request_path= "/forums/1/topics/2375" - /* XXX request url does include fragment? */ - ,.request_url= "/forums/1/topics/2375?page=1#posts-17408" - ,.num_headers= 0 - ,.body= "" - } - -#define GET_NO_HEADERS_NO_BODY 4 -, {.name= "get no headers no body" - ,.type= HTTP_REQUEST - ,.raw= "GET /get_no_headers_no_body/world HTTP/1.1\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE /* would need Connection: close */ - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_GET - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/get_no_headers_no_body/world" - ,.request_url= "/get_no_headers_no_body/world" - ,.num_headers= 0 - ,.body= "" - } - -#define GET_ONE_HEADER_NO_BODY 5 -, {.name= "get one header no body" - ,.type= HTTP_REQUEST - ,.raw= "GET /get_one_header_no_body HTTP/1.1\r\n" - "Accept: */*\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE /* would need Connection: close */ - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_GET - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/get_one_header_no_body" - ,.request_url= "/get_one_header_no_body" - ,.num_headers= 1 - ,.headers= - { { "Accept" , "*/*" } - } - ,.body= "" - } - -#define GET_FUNKY_CONTENT_LENGTH 6 -, {.name= "get funky content length body hello" - ,.type= HTTP_REQUEST - ,.raw= "GET /get_funky_content_length_body_hello HTTP/1.0\r\n" - "conTENT-Length: 5\r\n" - "\r\n" - "HELLO" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 0 - ,.method= HTTP_GET - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/get_funky_content_length_body_hello" - ,.request_url= "/get_funky_content_length_body_hello" - ,.num_headers= 1 - ,.headers= - { { "conTENT-Length" , "5" } - } - ,.body= "HELLO" - } - -#define POST_IDENTITY_BODY_WORLD 7 -, {.name= "post identity body world" - ,.type= HTTP_REQUEST - ,.raw= "POST /post_identity_body_world?q=search#hey HTTP/1.1\r\n" - "Accept: */*\r\n" - "Transfer-Encoding: identity\r\n" - "Content-Length: 5\r\n" - "\r\n" - "World" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_POST - ,.query_string= "q=search" - ,.fragment= "hey" - ,.request_path= "/post_identity_body_world" - ,.request_url= "/post_identity_body_world?q=search#hey" - ,.num_headers= 3 - ,.headers= - { { "Accept", "*/*" } - , { "Transfer-Encoding", "identity" } - , { "Content-Length", "5" } - } - ,.body= "World" - } - -#define POST_CHUNKED_ALL_YOUR_BASE 8 -, {.name= "post - chunked body: all your base are belong to us" - ,.type= HTTP_REQUEST - ,.raw= "POST /post_chunked_all_your_base HTTP/1.1\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "1e\r\nall your base are belong to us\r\n" - "0\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_POST - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/post_chunked_all_your_base" - ,.request_url= "/post_chunked_all_your_base" - ,.num_headers= 1 - ,.headers= - { { "Transfer-Encoding" , "chunked" } - } - ,.body= "all your base are belong to us" - } - -#define TWO_CHUNKS_MULT_ZERO_END 9 -, {.name= "two chunks ; triple zero ending" - ,.type= HTTP_REQUEST - ,.raw= "POST /two_chunks_mult_zero_end HTTP/1.1\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "5\r\nhello\r\n" - "6\r\n world\r\n" - "000\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_POST - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/two_chunks_mult_zero_end" - ,.request_url= "/two_chunks_mult_zero_end" - ,.num_headers= 1 - ,.headers= - { { "Transfer-Encoding", "chunked" } - } - ,.body= "hello world" - } - -#define CHUNKED_W_TRAILING_HEADERS 10 -, {.name= "chunked with trailing headers. blech." - ,.type= HTTP_REQUEST - ,.raw= "POST /chunked_w_trailing_headers HTTP/1.1\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "5\r\nhello\r\n" - "6\r\n world\r\n" - "0\r\n" - "Vary: *\r\n" - "Content-Type: text/plain\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_POST - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/chunked_w_trailing_headers" - ,.request_url= "/chunked_w_trailing_headers" - ,.num_headers= 3 - ,.headers= - { { "Transfer-Encoding", "chunked" } - , { "Vary", "*" } - , { "Content-Type", "text/plain" } - } - ,.body= "hello world" - } - -#define CHUNKED_W_BULLSHIT_AFTER_LENGTH 11 -, {.name= "with bullshit after the length" - ,.type= HTTP_REQUEST - ,.raw= "POST /chunked_w_bullshit_after_length HTTP/1.1\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "5; ihatew3;whatthefuck=aretheseparametersfor\r\nhello\r\n" - "6; blahblah; blah\r\n world\r\n" - "0\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_POST - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/chunked_w_bullshit_after_length" - ,.request_url= "/chunked_w_bullshit_after_length" - ,.num_headers= 1 - ,.headers= - { { "Transfer-Encoding", "chunked" } - } - ,.body= "hello world" - } - -#define WITH_QUOTES 12 -, {.name= "with quotes" - ,.type= HTTP_REQUEST - ,.raw= "GET /with_\"stupid\"_quotes?foo=\"bar\" HTTP/1.1\r\n\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_GET - ,.query_string= "foo=\"bar\"" - ,.fragment= "" - ,.request_path= "/with_\"stupid\"_quotes" - ,.request_url= "/with_\"stupid\"_quotes?foo=\"bar\"" - ,.num_headers= 0 - ,.headers= { } - ,.body= "" - } - -#define APACHEBENCH_GET 13 -/* The server receiving this request SHOULD NOT wait for EOF - * to know that content-length == 0. - * How to represent this in a unit test? message_complete_on_eof - * Compare with NO_CONTENT_LENGTH_RESPONSE. - */ -, {.name = "apachebench get" - ,.type= HTTP_REQUEST - ,.raw= "GET /test HTTP/1.0\r\n" - "Host: 0.0.0.0:5000\r\n" - "User-Agent: ApacheBench/2.3\r\n" - "Accept: */*\r\n\r\n" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 0 - ,.method= HTTP_GET - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/test" - ,.request_url= "/test" - ,.num_headers= 3 - ,.headers= { { "Host", "0.0.0.0:5000" } - , { "User-Agent", "ApacheBench/2.3" } - , { "Accept", "*/*" } - } - ,.body= "" - } - -#define QUERY_URL_WITH_QUESTION_MARK_GET 14 -/* Some clients include '?' characters in query strings. - */ -, {.name = "query url with question mark" - ,.type= HTTP_REQUEST - ,.raw= "GET /test.cgi?foo=bar?baz HTTP/1.1\r\n\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_GET - ,.query_string= "foo=bar?baz" - ,.fragment= "" - ,.request_path= "/test.cgi" - ,.request_url= "/test.cgi?foo=bar?baz" - ,.num_headers= 0 - ,.headers= {} - ,.body= "" - } - -#define PREFIX_NEWLINE_GET 15 -/* Some clients, especially after a POST in a keep-alive connection, - * will send an extra CRLF before the next request - */ -, {.name = "newline prefix get" - ,.type= HTTP_REQUEST - ,.raw= "\r\nGET /test HTTP/1.1\r\n\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_GET - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/test" - ,.request_url= "/test" - ,.num_headers= 0 - ,.headers= { } - ,.body= "" - } - -#define UPGRADE_REQUEST 16 -, {.name = "upgrade request" - ,.type= HTTP_REQUEST - ,.raw= "GET /demo HTTP/1.1\r\n" - "Host: example.com\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n" - "Sec-WebSocket-Protocol: sample\r\n" - "Upgrade: WebSocket\r\n" - "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n" - "Origin: http://example.com\r\n" - "\r\n" - "Hot diggity dogg" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_GET - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/demo" - ,.request_url= "/demo" - ,.num_headers= 7 - ,.upgrade="Hot diggity dogg" - ,.headers= { { "Host", "example.com" } - , { "Connection", "Upgrade" } - , { "Sec-WebSocket-Key2", "12998 5 Y3 1 .P00" } - , { "Sec-WebSocket-Protocol", "sample" } - , { "Upgrade", "WebSocket" } - , { "Sec-WebSocket-Key1", "4 @1 46546xW%0l 1 5" } - , { "Origin", "http://example.com" } - } - ,.body= "" - } - -#define CONNECT_REQUEST 17 -, {.name = "connect request" - ,.type= HTTP_REQUEST - ,.raw= "CONNECT 0-home0.netscape.com:443 HTTP/1.0\r\n" - "User-agent: Mozilla/1.1N\r\n" - "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n" - "\r\n" - "some data\r\n" - "and yet even more data" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 0 - ,.method= HTTP_CONNECT - ,.query_string= "" - ,.fragment= "" - ,.request_path= "" - ,.request_url= "0-home0.netscape.com:443" - ,.num_headers= 2 - ,.upgrade="some data\r\nand yet even more data" - ,.headers= { { "User-agent", "Mozilla/1.1N" } - , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" } - } - ,.body= "" - } - -#define REPORT_REQ 18 -, {.name= "report request" - ,.type= HTTP_REQUEST - ,.raw= "REPORT /test HTTP/1.1\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_REPORT - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/test" - ,.request_url= "/test" - ,.num_headers= 0 - ,.headers= {} - ,.body= "" - } - -#define NO_HTTP_VERSION 19 -, {.name= "request with no http version" - ,.type= HTTP_REQUEST - ,.raw= "GET /\r\n" - "\r\n" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= FALSE - ,.http_major= 0 - ,.http_minor= 9 - ,.method= HTTP_GET - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/" - ,.request_url= "/" - ,.num_headers= 0 - ,.headers= {} - ,.body= "" - } - -#define MSEARCH_REQ 20 -, {.name= "m-search request" - ,.type= HTTP_REQUEST - ,.raw= "M-SEARCH * HTTP/1.1\r\n" - "HOST: 239.255.255.250:1900\r\n" - "MAN: \"ssdp:discover\"\r\n" - "ST: \"ssdp:all\"\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_MSEARCH - ,.query_string= "" - ,.fragment= "" - ,.request_path= "*" - ,.request_url= "*" - ,.num_headers= 3 - ,.headers= { { "HOST", "239.255.255.250:1900" } - , { "MAN", "\"ssdp:discover\"" } - , { "ST", "\"ssdp:all\"" } - } - ,.body= "" - } - -#define LINE_FOLDING_IN_HEADER 21 -, {.name= "line folding in header value" - ,.type= HTTP_REQUEST - ,.raw= "GET / HTTP/1.1\r\n" - "Line1: abc\r\n" - "\tdef\r\n" - " ghi\r\n" - "\t\tjkl\r\n" - " mno \r\n" - "\t \tqrs\r\n" - "Line2: \t line2\t\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_GET - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/" - ,.request_url= "/" - ,.num_headers= 2 - ,.headers= { { "Line1", "abcdefghijklmno qrs" } - , { "Line2", "line2\t" } - } - ,.body= "" - } - - -#define QUERY_TERMINATED_HOST 22 -, {.name= "host terminated by a query string" - ,.type= HTTP_REQUEST - ,.raw= "GET http://hypnotoad.org?hail=all HTTP/1.1\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_GET - ,.query_string= "hail=all" - ,.fragment= "" - ,.request_path= "" - ,.request_url= "http://hypnotoad.org?hail=all" - ,.host= "hypnotoad.org" - ,.num_headers= 0 - ,.headers= { } - ,.body= "" - } - -#define QUERY_TERMINATED_HOSTPORT 23 -, {.name= "host:port terminated by a query string" - ,.type= HTTP_REQUEST - ,.raw= "GET http://hypnotoad.org:1234?hail=all HTTP/1.1\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_GET - ,.query_string= "hail=all" - ,.fragment= "" - ,.request_path= "" - ,.request_url= "http://hypnotoad.org:1234?hail=all" - ,.host= "hypnotoad.org" - ,.port= 1234 - ,.num_headers= 0 - ,.headers= { } - ,.body= "" - } - -#define SPACE_TERMINATED_HOSTPORT 24 -, {.name= "host:port terminated by a space" - ,.type= HTTP_REQUEST - ,.raw= "GET http://hypnotoad.org:1234 HTTP/1.1\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_GET - ,.query_string= "" - ,.fragment= "" - ,.request_path= "" - ,.request_url= "http://hypnotoad.org:1234" - ,.host= "hypnotoad.org" - ,.port= 1234 - ,.num_headers= 0 - ,.headers= { } - ,.body= "" - } - -#define PATCH_REQ 25 -, {.name = "PATCH request" - ,.type= HTTP_REQUEST - ,.raw= "PATCH /file.txt HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "Content-Type: application/example\r\n" - "If-Match: \"e0023aa4e\"\r\n" - "Content-Length: 10\r\n" - "\r\n" - "cccccccccc" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_PATCH - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/file.txt" - ,.request_url= "/file.txt" - ,.num_headers= 4 - ,.headers= { { "Host", "www.example.com" } - , { "Content-Type", "application/example" } - , { "If-Match", "\"e0023aa4e\"" } - , { "Content-Length", "10" } - } - ,.body= "cccccccccc" - } - -#define CONNECT_CAPS_REQUEST 26 -, {.name = "connect caps request" - ,.type= HTTP_REQUEST - ,.raw= "CONNECT HOME0.NETSCAPE.COM:443 HTTP/1.0\r\n" - "User-agent: Mozilla/1.1N\r\n" - "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n" - "\r\n" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 0 - ,.method= HTTP_CONNECT - ,.query_string= "" - ,.fragment= "" - ,.request_path= "" - ,.request_url= "HOME0.NETSCAPE.COM:443" - ,.num_headers= 2 - ,.upgrade="" - ,.headers= { { "User-agent", "Mozilla/1.1N" } - , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" } - } - ,.body= "" - } - -#if !HTTP_PARSER_STRICT -#define UTF8_PATH_REQ 27 -, {.name= "utf-8 path request" - ,.type= HTTP_REQUEST - ,.raw= "GET /δ¶/δt/pope?q=1#narf HTTP/1.1\r\n" - "Host: github.com\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_GET - ,.query_string= "q=1" - ,.fragment= "narf" - ,.request_path= "/δ¶/δt/pope" - ,.request_url= "/δ¶/δt/pope?q=1#narf" - ,.num_headers= 1 - ,.headers= { {"Host", "github.com" } - } - ,.body= "" - } - -#define HOSTNAME_UNDERSCORE 28 -, {.name = "hostname underscore" - ,.type= HTTP_REQUEST - ,.raw= "CONNECT home_0.netscape.com:443 HTTP/1.0\r\n" - "User-agent: Mozilla/1.1N\r\n" - "Proxy-authorization: basic aGVsbG86d29ybGQ=\r\n" - "\r\n" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 0 - ,.method= HTTP_CONNECT - ,.query_string= "" - ,.fragment= "" - ,.request_path= "" - ,.request_url= "home_0.netscape.com:443" - ,.num_headers= 2 - ,.upgrade="" - ,.headers= { { "User-agent", "Mozilla/1.1N" } - , { "Proxy-authorization", "basic aGVsbG86d29ybGQ=" } - } - ,.body= "" - } -#endif /* !HTTP_PARSER_STRICT */ - -/* see https://github.com/ry/http-parser/issues/47 */ -#define EAT_TRAILING_CRLF_NO_CONNECTION_CLOSE 29 -, {.name = "eat CRLF between requests, no \"Connection: close\" header" - ,.raw= "POST / HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "Content-Type: application/x-www-form-urlencoded\r\n" - "Content-Length: 4\r\n" - "\r\n" - "q=42\r\n" /* note the trailing CRLF */ - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_POST - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/" - ,.request_url= "/" - ,.num_headers= 3 - ,.upgrade= 0 - ,.headers= { { "Host", "www.example.com" } - , { "Content-Type", "application/x-www-form-urlencoded" } - , { "Content-Length", "4" } - } - ,.body= "q=42" - } - -/* see https://github.com/ry/http-parser/issues/47 */ -#define EAT_TRAILING_CRLF_WITH_CONNECTION_CLOSE 30 -, {.name = "eat CRLF between requests even if \"Connection: close\" is set" - ,.raw= "POST / HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "Content-Type: application/x-www-form-urlencoded\r\n" - "Content-Length: 4\r\n" - "Connection: close\r\n" - "\r\n" - "q=42\r\n" /* note the trailing CRLF */ - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= FALSE /* input buffer isn't empty when on_message_complete is called */ - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_POST - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/" - ,.request_url= "/" - ,.num_headers= 4 - ,.upgrade= 0 - ,.headers= { { "Host", "www.example.com" } - , { "Content-Type", "application/x-www-form-urlencoded" } - , { "Content-Length", "4" } - , { "Connection", "close" } - } - ,.body= "q=42" - } - -#define PURGE_REQ 31 -, {.name = "PURGE request" - ,.type= HTTP_REQUEST - ,.raw= "PURGE /file.txt HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_PURGE - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/file.txt" - ,.request_url= "/file.txt" - ,.num_headers= 1 - ,.headers= { { "Host", "www.example.com" } } - ,.body= "" - } - -#define SEARCH_REQ 32 -, {.name = "SEARCH request" - ,.type= HTTP_REQUEST - ,.raw= "SEARCH / HTTP/1.1\r\n" - "Host: www.example.com\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_SEARCH - ,.query_string= "" - ,.fragment= "" - ,.request_path= "/" - ,.request_url= "/" - ,.num_headers= 1 - ,.headers= { { "Host", "www.example.com" } } - ,.body= "" - } - -#define PROXY_WITH_BASIC_AUTH 33 -, {.name= "host:port and basic_auth" - ,.type= HTTP_REQUEST - ,.raw= "GET http://a%12:b!&*$@hypnotoad.org:1234/toto HTTP/1.1\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.method= HTTP_GET - ,.fragment= "" - ,.request_path= "/toto" - ,.request_url= "http://a%12:b!&*$@hypnotoad.org:1234/toto" - ,.host= "hypnotoad.org" - ,.userinfo= "a%12:b!&*$" - ,.port= 1234 - ,.num_headers= 0 - ,.headers= { } - ,.body= "" - } - - -, {.name= NULL } /* sentinel */ -}; - -/* * R E S P O N S E S * */ -const struct message responses[] = -#define GOOGLE_301 0 -{ {.name= "google 301" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.1 301 Moved Permanently\r\n" - "Location: http://www.google.com/\r\n" - "Content-Type: text/html; charset=UTF-8\r\n" - "Date: Sun, 26 Apr 2009 11:11:49 GMT\r\n" - "Expires: Tue, 26 May 2009 11:11:49 GMT\r\n" - "X-$PrototypeBI-Version: 1.6.0.3\r\n" /* $ char in header field */ - "Cache-Control: public, max-age=2592000\r\n" - "Server: gws\r\n" - "Content-Length: 219 \r\n" - "\r\n" - "\n" - "301 Moved\n" - "

301 Moved

\n" - "The document has moved\n" - "here.\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.status_code= 301 - ,.num_headers= 8 - ,.headers= - { { "Location", "http://www.google.com/" } - , { "Content-Type", "text/html; charset=UTF-8" } - , { "Date", "Sun, 26 Apr 2009 11:11:49 GMT" } - , { "Expires", "Tue, 26 May 2009 11:11:49 GMT" } - , { "X-$PrototypeBI-Version", "1.6.0.3" } - , { "Cache-Control", "public, max-age=2592000" } - , { "Server", "gws" } - , { "Content-Length", "219 " } - } - ,.body= "\n" - "301 Moved\n" - "

301 Moved

\n" - "The document has moved\n" - "here.\r\n" - "\r\n" - } - -#define NO_CONTENT_LENGTH_RESPONSE 1 -/* The client should wait for the server's EOF. That is, when content-length - * is not specified, and "Connection: close", the end of body is specified - * by the EOF. - * Compare with APACHEBENCH_GET - */ -, {.name= "no content-length response" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.1 200 OK\r\n" - "Date: Tue, 04 Aug 2009 07:59:32 GMT\r\n" - "Server: Apache\r\n" - "X-Powered-By: Servlet/2.5 JSP/2.1\r\n" - "Content-Type: text/xml; charset=utf-8\r\n" - "Connection: close\r\n" - "\r\n" - "\n" - "\n" - " \n" - " \n" - " SOAP-ENV:Client\n" - " Client Error\n" - " \n" - " \n" - "" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= TRUE - ,.http_major= 1 - ,.http_minor= 1 - ,.status_code= 200 - ,.num_headers= 5 - ,.headers= - { { "Date", "Tue, 04 Aug 2009 07:59:32 GMT" } - , { "Server", "Apache" } - , { "X-Powered-By", "Servlet/2.5 JSP/2.1" } - , { "Content-Type", "text/xml; charset=utf-8" } - , { "Connection", "close" } - } - ,.body= "\n" - "\n" - " \n" - " \n" - " SOAP-ENV:Client\n" - " Client Error\n" - " \n" - " \n" - "" - } - -#define NO_HEADERS_NO_BODY_404 2 -, {.name= "404 no headers no body" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.1 404 Not Found\r\n\r\n" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= TRUE - ,.http_major= 1 - ,.http_minor= 1 - ,.status_code= 404 - ,.num_headers= 0 - ,.headers= {} - ,.body_size= 0 - ,.body= "" - } - -#define NO_REASON_PHRASE 3 -, {.name= "301 no response phrase" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.1 301\r\n\r\n" - ,.should_keep_alive = FALSE - ,.message_complete_on_eof= TRUE - ,.http_major= 1 - ,.http_minor= 1 - ,.status_code= 301 - ,.num_headers= 0 - ,.headers= {} - ,.body= "" - } - -#define TRAILING_SPACE_ON_CHUNKED_BODY 4 -, {.name="200 trailing space on chunked body" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.1 200 OK\r\n" - "Content-Type: text/plain\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "25 \r\n" - "This is the data in the first chunk\r\n" - "\r\n" - "1C\r\n" - "and this is the second one\r\n" - "\r\n" - "0 \r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.status_code= 200 - ,.num_headers= 2 - ,.headers= - { {"Content-Type", "text/plain" } - , {"Transfer-Encoding", "chunked" } - } - ,.body_size = 37+28 - ,.body = - "This is the data in the first chunk\r\n" - "and this is the second one\r\n" - - } - -#define NO_CARRIAGE_RET 5 -, {.name="no carriage ret" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.1 200 OK\n" - "Content-Type: text/html; charset=utf-8\n" - "Connection: close\n" - "\n" - "these headers are from http://news.ycombinator.com/" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= TRUE - ,.http_major= 1 - ,.http_minor= 1 - ,.status_code= 200 - ,.num_headers= 2 - ,.headers= - { {"Content-Type", "text/html; charset=utf-8" } - , {"Connection", "close" } - } - ,.body= "these headers are from http://news.ycombinator.com/" - } - -#define PROXY_CONNECTION 6 -, {.name="proxy connection" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.1 200 OK\r\n" - "Content-Type: text/html; charset=UTF-8\r\n" - "Content-Length: 11\r\n" - "Proxy-Connection: close\r\n" - "Date: Thu, 31 Dec 2009 20:55:48 +0000\r\n" - "\r\n" - "hello world" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.status_code= 200 - ,.num_headers= 4 - ,.headers= - { {"Content-Type", "text/html; charset=UTF-8" } - , {"Content-Length", "11" } - , {"Proxy-Connection", "close" } - , {"Date", "Thu, 31 Dec 2009 20:55:48 +0000"} - } - ,.body= "hello world" - } - -#define UNDERSTORE_HEADER_KEY 7 - // shown by - // curl -o /dev/null -v "http://ad.doubleclick.net/pfadx/DARTSHELLCONFIGXML;dcmt=text/xml;" -, {.name="underscore header key" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.1 200 OK\r\n" - "Server: DCLK-AdSvr\r\n" - "Content-Type: text/xml\r\n" - "Content-Length: 0\r\n" - "DCLK_imp: v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o\r\n\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.status_code= 200 - ,.num_headers= 4 - ,.headers= - { {"Server", "DCLK-AdSvr" } - , {"Content-Type", "text/xml" } - , {"Content-Length", "0" } - , {"DCLK_imp", "v7;x;114750856;0-0;0;17820020;0/0;21603567/21621457/1;;~okv=;dcmt=text/xml;;~cs=o" } - } - ,.body= "" - } - -#define BONJOUR_MADAME_FR 8 -/* The client should not merge two headers fields when the first one doesn't - * have a value. - */ -, {.name= "bonjourmadame.fr" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.0 301 Moved Permanently\r\n" - "Date: Thu, 03 Jun 2010 09:56:32 GMT\r\n" - "Server: Apache/2.2.3 (Red Hat)\r\n" - "Cache-Control: public\r\n" - "Pragma: \r\n" - "Location: http://www.bonjourmadame.fr/\r\n" - "Vary: Accept-Encoding\r\n" - "Content-Length: 0\r\n" - "Content-Type: text/html; charset=UTF-8\r\n" - "Connection: keep-alive\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 0 - ,.status_code= 301 - ,.num_headers= 9 - ,.headers= - { { "Date", "Thu, 03 Jun 2010 09:56:32 GMT" } - , { "Server", "Apache/2.2.3 (Red Hat)" } - , { "Cache-Control", "public" } - , { "Pragma", "" } - , { "Location", "http://www.bonjourmadame.fr/" } - , { "Vary", "Accept-Encoding" } - , { "Content-Length", "0" } - , { "Content-Type", "text/html; charset=UTF-8" } - , { "Connection", "keep-alive" } - } - ,.body= "" - } - -#define RES_FIELD_UNDERSCORE 9 -/* Should handle spaces in header fields */ -, {.name= "field underscore" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.1 200 OK\r\n" - "Date: Tue, 28 Sep 2010 01:14:13 GMT\r\n" - "Server: Apache\r\n" - "Cache-Control: no-cache, must-revalidate\r\n" - "Expires: Mon, 26 Jul 1997 05:00:00 GMT\r\n" - ".et-Cookie: PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com\r\n" - "Vary: Accept-Encoding\r\n" - "_eep-Alive: timeout=45\r\n" /* semantic value ignored */ - "_onnection: Keep-Alive\r\n" /* semantic value ignored */ - "Transfer-Encoding: chunked\r\n" - "Content-Type: text/html\r\n" - "Connection: close\r\n" - "\r\n" - "0\r\n\r\n" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.status_code= 200 - ,.num_headers= 11 - ,.headers= - { { "Date", "Tue, 28 Sep 2010 01:14:13 GMT" } - , { "Server", "Apache" } - , { "Cache-Control", "no-cache, must-revalidate" } - , { "Expires", "Mon, 26 Jul 1997 05:00:00 GMT" } - , { ".et-Cookie", "PlaxoCS=1274804622353690521; path=/; domain=.plaxo.com" } - , { "Vary", "Accept-Encoding" } - , { "_eep-Alive", "timeout=45" } - , { "_onnection", "Keep-Alive" } - , { "Transfer-Encoding", "chunked" } - , { "Content-Type", "text/html" } - , { "Connection", "close" } - } - ,.body= "" - } - -#define NON_ASCII_IN_STATUS_LINE 10 -/* Should handle non-ASCII in status line */ -, {.name= "non-ASCII in status line" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.1 500 Oriëntatieprobleem\r\n" - "Date: Fri, 5 Nov 2010 23:07:12 GMT+2\r\n" - "Content-Length: 0\r\n" - "Connection: close\r\n" - "\r\n" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.status_code= 500 - ,.num_headers= 3 - ,.headers= - { { "Date", "Fri, 5 Nov 2010 23:07:12 GMT+2" } - , { "Content-Length", "0" } - , { "Connection", "close" } - } - ,.body= "" - } - -#define HTTP_VERSION_0_9 11 -/* Should handle HTTP/0.9 */ -, {.name= "http version 0.9" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/0.9 200 OK\r\n" - "\r\n" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= TRUE - ,.http_major= 0 - ,.http_minor= 9 - ,.status_code= 200 - ,.num_headers= 0 - ,.headers= - {} - ,.body= "" - } - -#define NO_CONTENT_LENGTH_NO_TRANSFER_ENCODING_RESPONSE 12 -/* The client should wait for the server's EOF. That is, when neither - * content-length nor transfer-encoding is specified, the end of body - * is specified by the EOF. - */ -, {.name= "neither content-length nor transfer-encoding response" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.1 200 OK\r\n" - "Content-Type: text/plain\r\n" - "\r\n" - "hello world" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= TRUE - ,.http_major= 1 - ,.http_minor= 1 - ,.status_code= 200 - ,.num_headers= 1 - ,.headers= - { { "Content-Type", "text/plain" } - } - ,.body= "hello world" - } - -#define NO_BODY_HTTP10_KA_200 13 -, {.name= "HTTP/1.0 with keep-alive and EOF-terminated 200 status" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.0 200 OK\r\n" - "Connection: keep-alive\r\n" - "\r\n" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= TRUE - ,.http_major= 1 - ,.http_minor= 0 - ,.status_code= 200 - ,.num_headers= 1 - ,.headers= - { { "Connection", "keep-alive" } - } - ,.body_size= 0 - ,.body= "" - } - -#define NO_BODY_HTTP10_KA_204 14 -, {.name= "HTTP/1.0 with keep-alive and a 204 status" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.0 204 No content\r\n" - "Connection: keep-alive\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 0 - ,.status_code= 204 - ,.num_headers= 1 - ,.headers= - { { "Connection", "keep-alive" } - } - ,.body_size= 0 - ,.body= "" - } - -#define NO_BODY_HTTP11_KA_200 15 -, {.name= "HTTP/1.1 with an EOF-terminated 200 status" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.1 200 OK\r\n" - "\r\n" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= TRUE - ,.http_major= 1 - ,.http_minor= 1 - ,.status_code= 200 - ,.num_headers= 0 - ,.headers={} - ,.body_size= 0 - ,.body= "" - } - -#define NO_BODY_HTTP11_KA_204 16 -, {.name= "HTTP/1.1 with a 204 status" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.1 204 No content\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.status_code= 204 - ,.num_headers= 0 - ,.headers={} - ,.body_size= 0 - ,.body= "" - } - -#define NO_BODY_HTTP11_NOKA_204 17 -, {.name= "HTTP/1.1 with a 204 status and keep-alive disabled" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.1 204 No content\r\n" - "Connection: close\r\n" - "\r\n" - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.status_code= 204 - ,.num_headers= 1 - ,.headers= - { { "Connection", "close" } - } - ,.body_size= 0 - ,.body= "" - } - -#define NO_BODY_HTTP11_KA_CHUNKED_200 18 -, {.name= "HTTP/1.1 with chunked endocing and a 200 response" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.1 200 OK\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "0\r\n" - "\r\n" - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.status_code= 200 - ,.num_headers= 1 - ,.headers= - { { "Transfer-Encoding", "chunked" } - } - ,.body_size= 0 - ,.body= "" - } - -#if !HTTP_PARSER_STRICT -#define SPACE_IN_FIELD_RES 19 -/* Should handle spaces in header fields */ -, {.name= "field space" - ,.type= HTTP_RESPONSE - ,.raw= "HTTP/1.1 200 OK\r\n" - "Server: Microsoft-IIS/6.0\r\n" - "X-Powered-By: ASP.NET\r\n" - "en-US Content-Type: text/xml\r\n" /* this is the problem */ - "Content-Type: text/xml\r\n" - "Content-Length: 16\r\n" - "Date: Fri, 23 Jul 2010 18:45:38 GMT\r\n" - "Connection: keep-alive\r\n" - "\r\n" - "hello" /* fake body */ - ,.should_keep_alive= TRUE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 1 - ,.status_code= 200 - ,.num_headers= 7 - ,.headers= - { { "Server", "Microsoft-IIS/6.0" } - , { "X-Powered-By", "ASP.NET" } - , { "en-US Content-Type", "text/xml" } - , { "Content-Type", "text/xml" } - , { "Content-Length", "16" } - , { "Date", "Fri, 23 Jul 2010 18:45:38 GMT" } - , { "Connection", "keep-alive" } - } - ,.body= "hello" - } -#endif /* !HTTP_PARSER_STRICT */ - -, {.name= NULL } /* sentinel */ -}; - -/* strnlen() is a POSIX.2008 addition. Can't rely on it being available so - * define it ourselves. - */ -size_t -strnlen(const char *s, size_t maxlen) -{ - const char *p; - - p = memchr(s, '\0', maxlen); - if (p == NULL) - return maxlen; - - return p - s; -} - -size_t -strlncat(char *dst, size_t len, const char *src, size_t n) -{ - size_t slen; - size_t dlen; - size_t rlen; - size_t ncpy; - - slen = strnlen(src, n); - dlen = strnlen(dst, len); - - if (dlen < len) { - rlen = len - dlen; - ncpy = slen < rlen ? slen : (rlen - 1); - memcpy(dst + dlen, src, ncpy); - dst[dlen + ncpy] = '\0'; - } - - assert(len > slen + dlen); - return slen + dlen; -} - -size_t -strlcat(char *dst, const char *src, size_t len) -{ - return strlncat(dst, len, src, (size_t) -1); -} - -size_t -strlncpy(char *dst, size_t len, const char *src, size_t n) -{ - size_t slen; - size_t ncpy; - - slen = strnlen(src, n); - - if (len > 0) { - ncpy = slen < len ? slen : (len - 1); - memcpy(dst, src, ncpy); - dst[ncpy] = '\0'; - } - - assert(len > slen); - return slen; -} - -size_t -strlcpy(char *dst, const char *src, size_t len) -{ - return strlncpy(dst, len, src, (size_t) -1); -} - -int -request_url_cb (http_parser *p, const char *buf, size_t len) -{ - assert(p == parser); - strlncat(messages[num_messages].request_url, - sizeof(messages[num_messages].request_url), - buf, - len); - return 0; -} - -int -status_complete_cb (http_parser *p) { - assert(p == parser); - p->data++; - return 0; -} - -int -header_field_cb (http_parser *p, const char *buf, size_t len) -{ - assert(p == parser); - struct message *m = &messages[num_messages]; - - if (m->last_header_element != FIELD) - m->num_headers++; - - strlncat(m->headers[m->num_headers-1][0], - sizeof(m->headers[m->num_headers-1][0]), - buf, - len); - - m->last_header_element = FIELD; - - return 0; -} - -int -header_value_cb (http_parser *p, const char *buf, size_t len) -{ - assert(p == parser); - struct message *m = &messages[num_messages]; - - strlncat(m->headers[m->num_headers-1][1], - sizeof(m->headers[m->num_headers-1][1]), - buf, - len); - - m->last_header_element = VALUE; - - return 0; -} - -void -check_body_is_final (const http_parser *p) -{ - if (messages[num_messages].body_is_final) { - fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 " - "on last on_body callback call " - "but it doesn't! ***\n\n"); - assert(0); - abort(); - } - messages[num_messages].body_is_final = http_body_is_final(p); -} - -int -body_cb (http_parser *p, const char *buf, size_t len) -{ - assert(p == parser); - strlncat(messages[num_messages].body, - sizeof(messages[num_messages].body), - buf, - len); - messages[num_messages].body_size += len; - check_body_is_final(p); - // printf("body_cb: '%s'\n", requests[num_messages].body); - return 0; -} - -int -count_body_cb (http_parser *p, const char *buf, size_t len) -{ - assert(p == parser); - assert(buf); - messages[num_messages].body_size += len; - check_body_is_final(p); - return 0; -} - -int -message_begin_cb (http_parser *p) -{ - assert(p == parser); - messages[num_messages].message_begin_cb_called = TRUE; - return 0; -} - -int -headers_complete_cb (http_parser *p) -{ - assert(p == parser); - messages[num_messages].method = parser->method; - messages[num_messages].status_code = parser->status_code; - messages[num_messages].http_major = parser->http_major; - messages[num_messages].http_minor = parser->http_minor; - messages[num_messages].headers_complete_cb_called = TRUE; - messages[num_messages].should_keep_alive = http_should_keep_alive(parser); - return 0; -} - -int -message_complete_cb (http_parser *p) -{ - assert(p == parser); - if (messages[num_messages].should_keep_alive != http_should_keep_alive(parser)) - { - fprintf(stderr, "\n\n *** Error http_should_keep_alive() should have same " - "value in both on_message_complete and on_headers_complete " - "but it doesn't! ***\n\n"); - assert(0); - abort(); - } - - if (messages[num_messages].body_size && - http_body_is_final(p) && - !messages[num_messages].body_is_final) - { - fprintf(stderr, "\n\n *** Error http_body_is_final() should return 1 " - "on last on_body callback call " - "but it doesn't! ***\n\n"); - assert(0); - abort(); - } - - messages[num_messages].message_complete_cb_called = TRUE; - - messages[num_messages].message_complete_on_eof = currently_parsing_eof; - - num_messages++; - return 0; -} - -/* These dontcall_* callbacks exist so that we can verify that when we're - * paused, no additional callbacks are invoked */ -int -dontcall_message_begin_cb (http_parser *p) -{ - if (p) { } // gcc - fprintf(stderr, "\n\n*** on_message_begin() called on paused parser ***\n\n"); - abort(); -} - -int -dontcall_header_field_cb (http_parser *p, const char *buf, size_t len) -{ - if (p || buf || len) { } // gcc - fprintf(stderr, "\n\n*** on_header_field() called on paused parser ***\n\n"); - abort(); -} - -int -dontcall_header_value_cb (http_parser *p, const char *buf, size_t len) -{ - if (p || buf || len) { } // gcc - fprintf(stderr, "\n\n*** on_header_value() called on paused parser ***\n\n"); - abort(); -} - -int -dontcall_request_url_cb (http_parser *p, const char *buf, size_t len) -{ - if (p || buf || len) { } // gcc - fprintf(stderr, "\n\n*** on_request_url() called on paused parser ***\n\n"); - abort(); -} - -int -dontcall_body_cb (http_parser *p, const char *buf, size_t len) -{ - if (p || buf || len) { } // gcc - fprintf(stderr, "\n\n*** on_body_cb() called on paused parser ***\n\n"); - abort(); -} - -int -dontcall_headers_complete_cb (http_parser *p) -{ - if (p) { } // gcc - fprintf(stderr, "\n\n*** on_headers_complete() called on paused " - "parser ***\n\n"); - abort(); -} - -int -dontcall_message_complete_cb (http_parser *p) -{ - if (p) { } // gcc - fprintf(stderr, "\n\n*** on_message_complete() called on paused " - "parser ***\n\n"); - abort(); -} - -static http_parser_settings settings_dontcall = - {.on_message_begin = dontcall_message_begin_cb - ,.on_header_field = dontcall_header_field_cb - ,.on_header_value = dontcall_header_value_cb - ,.on_url = dontcall_request_url_cb - ,.on_body = dontcall_body_cb - ,.on_headers_complete = dontcall_headers_complete_cb - ,.on_message_complete = dontcall_message_complete_cb - }; - -/* These pause_* callbacks always pause the parser and just invoke the regular - * callback that tracks content. Before returning, we overwrite the parser - * settings to point to the _dontcall variety so that we can verify that - * the pause actually did, you know, pause. */ -int -pause_message_begin_cb (http_parser *p) -{ - http_parser_pause(p, 1); - *current_pause_parser = settings_dontcall; - return message_begin_cb(p); -} - -int -pause_header_field_cb (http_parser *p, const char *buf, size_t len) -{ - http_parser_pause(p, 1); - *current_pause_parser = settings_dontcall; - return header_field_cb(p, buf, len); -} - -int -pause_header_value_cb (http_parser *p, const char *buf, size_t len) -{ - http_parser_pause(p, 1); - *current_pause_parser = settings_dontcall; - return header_value_cb(p, buf, len); -} - -int -pause_request_url_cb (http_parser *p, const char *buf, size_t len) -{ - http_parser_pause(p, 1); - *current_pause_parser = settings_dontcall; - return request_url_cb(p, buf, len); -} - -int -pause_body_cb (http_parser *p, const char *buf, size_t len) -{ - http_parser_pause(p, 1); - *current_pause_parser = settings_dontcall; - return body_cb(p, buf, len); -} - -int -pause_headers_complete_cb (http_parser *p) -{ - http_parser_pause(p, 1); - *current_pause_parser = settings_dontcall; - return headers_complete_cb(p); -} - -int -pause_message_complete_cb (http_parser *p) -{ - http_parser_pause(p, 1); - *current_pause_parser = settings_dontcall; - return message_complete_cb(p); -} - -static http_parser_settings settings_pause = - {.on_message_begin = pause_message_begin_cb - ,.on_header_field = pause_header_field_cb - ,.on_header_value = pause_header_value_cb - ,.on_url = pause_request_url_cb - ,.on_body = pause_body_cb - ,.on_headers_complete = pause_headers_complete_cb - ,.on_message_complete = pause_message_complete_cb - }; - -static http_parser_settings settings = - {.on_message_begin = message_begin_cb - ,.on_header_field = header_field_cb - ,.on_header_value = header_value_cb - ,.on_url = request_url_cb - ,.on_body = body_cb - ,.on_headers_complete = headers_complete_cb - ,.on_message_complete = message_complete_cb - }; - -static http_parser_settings settings_count_body = - {.on_message_begin = message_begin_cb - ,.on_header_field = header_field_cb - ,.on_header_value = header_value_cb - ,.on_url = request_url_cb - ,.on_body = count_body_cb - ,.on_headers_complete = headers_complete_cb - ,.on_message_complete = message_complete_cb - }; - -static http_parser_settings settings_null = - {.on_message_begin = 0 - ,.on_header_field = 0 - ,.on_header_value = 0 - ,.on_url = 0 - ,.on_body = 0 - ,.on_headers_complete = 0 - ,.on_message_complete = 0 - }; - -void -parser_init (enum http_parser_type type) -{ - num_messages = 0; - - assert(parser == NULL); - - parser = malloc(sizeof(http_parser)); - - http_parser_init(parser, type); - - memset(&messages, 0, sizeof messages); - -} - -void -parser_free () -{ - assert(parser); - free(parser); - parser = NULL; -} - -size_t parse (const char *buf, size_t len) -{ - size_t nparsed; - currently_parsing_eof = (len == 0); - nparsed = http_parser_execute(parser, &settings, buf, len); - return nparsed; -} - -size_t parse_count_body (const char *buf, size_t len) -{ - size_t nparsed; - currently_parsing_eof = (len == 0); - nparsed = http_parser_execute(parser, &settings_count_body, buf, len); - return nparsed; -} - -size_t parse_pause (const char *buf, size_t len) -{ - size_t nparsed; - http_parser_settings s = settings_pause; - - currently_parsing_eof = (len == 0); - current_pause_parser = &s; - nparsed = http_parser_execute(parser, current_pause_parser, buf, len); - return nparsed; -} - -static inline int -check_str_eq (const struct message *m, - const char *prop, - const char *expected, - const char *found) { - if ((expected == NULL) != (found == NULL)) { - printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name); - printf("expected %s\n", (expected == NULL) ? "NULL" : expected); - printf(" found %s\n", (found == NULL) ? "NULL" : found); - return 0; - } - if (expected != NULL && 0 != strcmp(expected, found)) { - printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name); - printf("expected '%s'\n", expected); - printf(" found '%s'\n", found); - return 0; - } - return 1; -} - -static inline int -check_num_eq (const struct message *m, - const char *prop, - int expected, - int found) { - if (expected != found) { - printf("\n*** Error: %s in '%s' ***\n\n", prop, m->name); - printf("expected %d\n", expected); - printf(" found %d\n", found); - return 0; - } - return 1; -} - -#define MESSAGE_CHECK_STR_EQ(expected, found, prop) \ - if (!check_str_eq(expected, #prop, expected->prop, found->prop)) return 0 - -#define MESSAGE_CHECK_NUM_EQ(expected, found, prop) \ - if (!check_num_eq(expected, #prop, expected->prop, found->prop)) return 0 - -#define MESSAGE_CHECK_URL_EQ(u, expected, found, prop, fn) \ -do { \ - char ubuf[256]; \ - \ - if ((u)->field_set & (1 << (fn))) { \ - memcpy(ubuf, (found)->request_url + (u)->field_data[(fn)].off, \ - (u)->field_data[(fn)].len); \ - ubuf[(u)->field_data[(fn)].len] = '\0'; \ - } else { \ - ubuf[0] = '\0'; \ - } \ - \ - check_str_eq(expected, #prop, expected->prop, ubuf); \ -} while(0) - -int -message_eq (int index, const struct message *expected) -{ - int i; - struct message *m = &messages[index]; - - MESSAGE_CHECK_NUM_EQ(expected, m, http_major); - MESSAGE_CHECK_NUM_EQ(expected, m, http_minor); - - if (expected->type == HTTP_REQUEST) { - MESSAGE_CHECK_NUM_EQ(expected, m, method); - } else { - MESSAGE_CHECK_NUM_EQ(expected, m, status_code); - } - - MESSAGE_CHECK_NUM_EQ(expected, m, should_keep_alive); - MESSAGE_CHECK_NUM_EQ(expected, m, message_complete_on_eof); - - assert(m->message_begin_cb_called); - assert(m->headers_complete_cb_called); - assert(m->message_complete_cb_called); - - - MESSAGE_CHECK_STR_EQ(expected, m, request_url); - - /* Check URL components; we can't do this w/ CONNECT since it doesn't - * send us a well-formed URL. - */ - if (*m->request_url && m->method != HTTP_CONNECT) { - struct http_parser_url u; - - if (http_parser_parse_url(m->request_url, strlen(m->request_url), 0, &u)) { - fprintf(stderr, "\n\n*** failed to parse URL %s ***\n\n", - m->request_url); - abort(); - } - - if (expected->host) { - MESSAGE_CHECK_URL_EQ(&u, expected, m, host, UF_HOST); - } - - if (expected->userinfo) { - MESSAGE_CHECK_URL_EQ(&u, expected, m, userinfo, UF_USERINFO); - } - - m->port = (u.field_set & (1 << UF_PORT)) ? - u.port : 0; - - MESSAGE_CHECK_URL_EQ(&u, expected, m, query_string, UF_QUERY); - MESSAGE_CHECK_URL_EQ(&u, expected, m, fragment, UF_FRAGMENT); - MESSAGE_CHECK_URL_EQ(&u, expected, m, request_path, UF_PATH); - MESSAGE_CHECK_NUM_EQ(expected, m, port); - } - - if (expected->body_size) { - MESSAGE_CHECK_NUM_EQ(expected, m, body_size); - } else { - MESSAGE_CHECK_STR_EQ(expected, m, body); - } - - MESSAGE_CHECK_NUM_EQ(expected, m, num_headers); - - int r; - for (i = 0; i < m->num_headers; i++) { - r = check_str_eq(expected, "header field", expected->headers[i][0], m->headers[i][0]); - if (!r) return 0; - r = check_str_eq(expected, "header value", expected->headers[i][1], m->headers[i][1]); - if (!r) return 0; - } - - MESSAGE_CHECK_STR_EQ(expected, m, upgrade); - - return 1; -} - -/* Given a sequence of varargs messages, return the number of them that the - * parser should successfully parse, taking into account that upgraded - * messages prevent all subsequent messages from being parsed. - */ -size_t -count_parsed_messages(const size_t nmsgs, ...) { - size_t i; - va_list ap; - - va_start(ap, nmsgs); - - for (i = 0; i < nmsgs; i++) { - struct message *m = va_arg(ap, struct message *); - - if (m->upgrade) { - va_end(ap); - return i + 1; - } - } - - va_end(ap); - return nmsgs; -} - -/* Given a sequence of bytes and the number of these that we were able to - * parse, verify that upgrade bodies are correct. - */ -void -upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) { - va_list ap; - size_t i; - size_t off = 0; - - va_start(ap, nmsgs); - - for (i = 0; i < nmsgs; i++) { - struct message *m = va_arg(ap, struct message *); - - off += strlen(m->raw); - - if (m->upgrade) { - off -= strlen(m->upgrade); - - /* Check the portion of the response after its specified upgrade */ - if (!check_str_eq(m, "upgrade", body + off, body + nread)) { - abort(); - } - - /* Fix up the response so that message_eq() will verify the beginning - * of the upgrade */ - *(body + nread + strlen(m->upgrade)) = '\0'; - messages[num_messages -1 ].upgrade = body + nread; - - va_end(ap); - return; - } - } - - va_end(ap); - printf("\n\n*** Error: expected a message with upgrade ***\n"); - - abort(); -} - -static void -print_error (const char *raw, size_t error_location) -{ - fprintf(stderr, "\n*** %s ***\n\n", - http_errno_description(HTTP_PARSER_ERRNO(parser))); - - int this_line = 0, char_len = 0; - size_t i, j, len = strlen(raw), error_location_line = 0; - for (i = 0; i < len; i++) { - if (i == error_location) this_line = 1; - switch (raw[i]) { - case '\r': - char_len = 2; - fprintf(stderr, "\\r"); - break; - - case '\n': - char_len = 2; - fprintf(stderr, "\\n\n"); - - if (this_line) goto print; - - error_location_line = 0; - continue; - - default: - char_len = 1; - fputc(raw[i], stderr); - break; - } - if (!this_line) error_location_line += char_len; - } - - fprintf(stderr, "[eof]\n"); - - print: - for (j = 0; j < error_location_line; j++) { - fputc(' ', stderr); - } - fprintf(stderr, "^\n\nerror location: %u\n", (unsigned int)error_location); -} - -void -test_preserve_data (void) -{ - char my_data[] = "application-specific data"; - http_parser parser; - parser.data = my_data; - http_parser_init(&parser, HTTP_REQUEST); - if (parser.data != my_data) { - printf("\n*** parser.data not preserved accross http_parser_init ***\n\n"); - abort(); - } -} - -struct url_test { - const char *name; - const char *url; - int is_connect; - struct http_parser_url u; - int rv; -}; - -const struct url_test url_tests[] = -{ {.name="proxy request" - ,.url="http://hostname/" - ,.is_connect=0 - ,.u= - {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH) - ,.port=0 - ,.field_data= - {{ 0, 4 } /* UF_SCHEMA */ - ,{ 7, 8 } /* UF_HOST */ - ,{ 0, 0 } /* UF_PORT */ - ,{ 15, 1 } /* UF_PATH */ - ,{ 0, 0 } /* UF_QUERY */ - ,{ 0, 0 } /* UF_FRAGMENT */ - ,{ 0, 0 } /* UF_USERINFO */ - } - } - ,.rv=0 - } - -, {.name="proxy request with port" - ,.url="http://hostname:444/" - ,.is_connect=0 - ,.u= - {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH) - ,.port=444 - ,.field_data= - {{ 0, 4 } /* UF_SCHEMA */ - ,{ 7, 8 } /* UF_HOST */ - ,{ 16, 3 } /* UF_PORT */ - ,{ 19, 1 } /* UF_PATH */ - ,{ 0, 0 } /* UF_QUERY */ - ,{ 0, 0 } /* UF_FRAGMENT */ - ,{ 0, 0 } /* UF_USERINFO */ - } - } - ,.rv=0 - } - -, {.name="CONNECT request" - ,.url="hostname:443" - ,.is_connect=1 - ,.u= - {.field_set=(1 << UF_HOST) | (1 << UF_PORT) - ,.port=443 - ,.field_data= - {{ 0, 0 } /* UF_SCHEMA */ - ,{ 0, 8 } /* UF_HOST */ - ,{ 9, 3 } /* UF_PORT */ - ,{ 0, 0 } /* UF_PATH */ - ,{ 0, 0 } /* UF_QUERY */ - ,{ 0, 0 } /* UF_FRAGMENT */ - ,{ 0, 0 } /* UF_USERINFO */ - } - } - ,.rv=0 - } - -, {.name="CONNECT request but not connect" - ,.url="hostname:443" - ,.is_connect=0 - ,.rv=1 - } - -, {.name="proxy ipv6 request" - ,.url="http://[1:2::3:4]/" - ,.is_connect=0 - ,.u= - {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH) - ,.port=0 - ,.field_data= - {{ 0, 4 } /* UF_SCHEMA */ - ,{ 8, 8 } /* UF_HOST */ - ,{ 0, 0 } /* UF_PORT */ - ,{ 17, 1 } /* UF_PATH */ - ,{ 0, 0 } /* UF_QUERY */ - ,{ 0, 0 } /* UF_FRAGMENT */ - ,{ 0, 0 } /* UF_USERINFO */ - } - } - ,.rv=0 - } - -, {.name="proxy ipv6 request with port" - ,.url="http://[1:2::3:4]:67/" - ,.is_connect=0 - ,.u= - {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PORT) | (1 << UF_PATH) - ,.port=67 - ,.field_data= - {{ 0, 4 } /* UF_SCHEMA */ - ,{ 8, 8 } /* UF_HOST */ - ,{ 18, 2 } /* UF_PORT */ - ,{ 20, 1 } /* UF_PATH */ - ,{ 0, 0 } /* UF_QUERY */ - ,{ 0, 0 } /* UF_FRAGMENT */ - ,{ 0, 0 } /* UF_USERINFO */ - } - } - ,.rv=0 - } - -, {.name="CONNECT ipv6 address" - ,.url="[1:2::3:4]:443" - ,.is_connect=1 - ,.u= - {.field_set=(1 << UF_HOST) | (1 << UF_PORT) - ,.port=443 - ,.field_data= - {{ 0, 0 } /* UF_SCHEMA */ - ,{ 1, 8 } /* UF_HOST */ - ,{ 11, 3 } /* UF_PORT */ - ,{ 0, 0 } /* UF_PATH */ - ,{ 0, 0 } /* UF_QUERY */ - ,{ 0, 0 } /* UF_FRAGMENT */ - ,{ 0, 0 } /* UF_USERINFO */ - } - } - ,.rv=0 - } - -, {.name="ipv4 in ipv6 address" - ,.url="http://[2001:0000:0000:0000:0000:0000:1.9.1.1]/" - ,.is_connect=0 - ,.u= - {.field_set=(1 << UF_SCHEMA) | (1 << UF_HOST) | (1 << UF_PATH) - ,.port=0 - ,.field_data= - {{ 0, 4 } /* UF_SCHEMA */ - ,{ 8, 37 } /* UF_HOST */ - ,{ 0, 0 } /* UF_PORT */ - ,{ 46, 1 } /* UF_PATH */ - ,{ 0, 0 } /* UF_QUERY */ - ,{ 0, 0 } /* UF_FRAGMENT */ - ,{ 0, 0 } /* UF_USERINFO */ - } - } - ,.rv=0 - } - -, {.name="extra ? in query string" - ,.url="http://a.tbcdn.cn/p/fp/2010c/??fp-header-min.css,fp-base-min.css," - "fp-channel-min.css,fp-product-min.css,fp-mall-min.css,fp-category-min.css," - "fp-sub-min.css,fp-gdp4p-min.css,fp-css3-min.css,fp-misc-min.css?t=20101022.css" - ,.is_connect=0 - ,.u= - {.field_set=(1<field_set, u->port); - for (i = 0; i < UF_MAX; i++) { - if ((u->field_set & (1 << i)) == 0) { - printf("\tfield_data[%u]: unset\n", i); - continue; - } - - printf("\tfield_data[%u]: off: %u len: %u part: \"%.*s\n\"", - i, - u->field_data[i].off, - u->field_data[i].len, - u->field_data[i].len, - url + u->field_data[i].off); - } -} - -void -test_parse_url (void) -{ - struct http_parser_url u; - const struct url_test *test; - unsigned int i; - int rv; - - for (i = 0; i < (sizeof(url_tests) / sizeof(url_tests[0])); i++) { - test = &url_tests[i]; - memset(&u, 0, sizeof(u)); - - rv = http_parser_parse_url(test->url, - strlen(test->url), - test->is_connect, - &u); - - if (test->rv == 0) { - if (rv != 0) { - printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, " - "unexpected rv %d ***\n\n", test->url, test->name, rv); - abort(); - } - - if (memcmp(&u, &test->u, sizeof(u)) != 0) { - printf("\n*** http_parser_parse_url(\"%s\") \"%s\" failed ***\n", - test->url, test->name); - - printf("target http_parser_url:\n"); - dump_url(test->url, &test->u); - printf("result http_parser_url:\n"); - dump_url(test->url, &u); - - abort(); - } - } else { - /* test->rv != 0 */ - if (rv == 0) { - printf("\n*** http_parser_parse_url(\"%s\") \"%s\" test failed, " - "unexpected rv %d ***\n\n", test->url, test->name, rv); - abort(); - } - } - } -} - -void -test_method_str (void) -{ - assert(0 == strcmp("GET", http_method_str(HTTP_GET))); - assert(0 == strcmp("", http_method_str(1337))); -} - -void -test_message (const struct message *message) -{ - size_t raw_len = strlen(message->raw); - size_t msg1len; - for (msg1len = 0; msg1len < raw_len; msg1len++) { - parser_init(message->type); - - size_t read; - const char *msg1 = message->raw; - const char *msg2 = msg1 + msg1len; - size_t msg2len = raw_len - msg1len; - - if (msg1len) { - read = parse(msg1, msg1len); - - if (message->upgrade && parser->upgrade) { - messages[num_messages - 1].upgrade = msg1 + read; - goto test; - } - - if (read != msg1len) { - print_error(msg1, read); - abort(); - } - } - - - read = parse(msg2, msg2len); - - if (message->upgrade && parser->upgrade) { - messages[num_messages - 1].upgrade = msg2 + read; - goto test; - } - - if (read != msg2len) { - print_error(msg2, read); - abort(); - } - - read = parse(NULL, 0); - - if (read != 0) { - print_error(message->raw, read); - abort(); - } - - test: - - if (num_messages != 1) { - printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name); - abort(); - } - - if(!message_eq(0, message)) abort(); - - parser_free(); - } -} - -void -test_message_count_body (const struct message *message) -{ - parser_init(message->type); - - size_t read; - size_t l = strlen(message->raw); - size_t i, toread; - size_t chunk = 4024; - - for (i = 0; i < l; i+= chunk) { - toread = MIN(l-i, chunk); - read = parse_count_body(message->raw + i, toread); - if (read != toread) { - print_error(message->raw, read); - abort(); - } - } - - - read = parse_count_body(NULL, 0); - if (read != 0) { - print_error(message->raw, read); - abort(); - } - - if (num_messages != 1) { - printf("\n*** num_messages != 1 after testing '%s' ***\n\n", message->name); - abort(); - } - - if(!message_eq(0, message)) abort(); - - parser_free(); -} - -void -test_simple (const char *buf, enum http_errno err_expected) -{ - parser_init(HTTP_REQUEST); - - size_t parsed; - int pass; - enum http_errno err; - - parsed = parse(buf, strlen(buf)); - pass = (parsed == strlen(buf)); - err = HTTP_PARSER_ERRNO(parser); - parsed = parse(NULL, 0); - pass &= (parsed == 0); - - parser_free(); - - /* In strict mode, allow us to pass with an unexpected HPE_STRICT as - * long as the caller isn't expecting success. - */ -#if HTTP_PARSER_STRICT - if (err_expected != err && err_expected != HPE_OK && err != HPE_STRICT) { -#else - if (err_expected != err) { -#endif - fprintf(stderr, "\n*** test_simple expected %s, but saw %s ***\n\n%s\n", - http_errno_name(err_expected), http_errno_name(err), buf); - abort(); - } -} - -void -test_header_overflow_error (int req) -{ - http_parser parser; - http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE); - size_t parsed; - const char *buf; - buf = req ? "GET / HTTP/1.1\r\n" : "HTTP/1.0 200 OK\r\n"; - parsed = http_parser_execute(&parser, &settings_null, buf, strlen(buf)); - assert(parsed == strlen(buf)); - - buf = "header-key: header-value\r\n"; - size_t buflen = strlen(buf); - - int i; - for (i = 0; i < 10000; i++) { - parsed = http_parser_execute(&parser, &settings_null, buf, buflen); - if (parsed != buflen) { - //fprintf(stderr, "error found on iter %d\n", i); - assert(HTTP_PARSER_ERRNO(&parser) == HPE_HEADER_OVERFLOW); - return; - } - } - - fprintf(stderr, "\n*** Error expected but none in header overflow test ***\n"); - abort(); -} - -static void -test_content_length_overflow (const char *buf, size_t buflen, int expect_ok) -{ - http_parser parser; - http_parser_init(&parser, HTTP_RESPONSE); - http_parser_execute(&parser, &settings_null, buf, buflen); - - if (expect_ok) - assert(HTTP_PARSER_ERRNO(&parser) == HPE_OK); - else - assert(HTTP_PARSER_ERRNO(&parser) == HPE_INVALID_CONTENT_LENGTH); -} - -void -test_header_content_length_overflow_error (void) -{ -#define X(size) \ - "HTTP/1.1 200 OK\r\n" \ - "Content-Length: " #size "\r\n" \ - "\r\n" - const char a[] = X(18446744073709551614); /* 2^64-2 */ - const char b[] = X(18446744073709551615); /* 2^64-1 */ - const char c[] = X(18446744073709551616); /* 2^64 */ -#undef X - test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */ - test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */ - test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */ -} - -void -test_chunk_content_length_overflow_error (void) -{ -#define X(size) \ - "HTTP/1.1 200 OK\r\n" \ - "Transfer-Encoding: chunked\r\n" \ - "\r\n" \ - #size "\r\n" \ - "..." - const char a[] = X(FFFFFFFFFFFFFFFE); /* 2^64-2 */ - const char b[] = X(FFFFFFFFFFFFFFFF); /* 2^64-1 */ - const char c[] = X(10000000000000000); /* 2^64 */ -#undef X - test_content_length_overflow(a, sizeof(a) - 1, 1); /* expect ok */ - test_content_length_overflow(b, sizeof(b) - 1, 0); /* expect failure */ - test_content_length_overflow(c, sizeof(c) - 1, 0); /* expect failure */ -} - -void -test_no_overflow_long_body (int req, size_t length) -{ - http_parser parser; - http_parser_init(&parser, req ? HTTP_REQUEST : HTTP_RESPONSE); - size_t parsed; - size_t i; - char buf1[3000]; - size_t buf1len = sprintf(buf1, "%s\r\nConnection: Keep-Alive\r\nContent-Length: %lu\r\n\r\n", - req ? "POST / HTTP/1.0" : "HTTP/1.0 200 OK", (unsigned long)length); - parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len); - if (parsed != buf1len) - goto err; - - for (i = 0; i < length; i++) { - char foo = 'a'; - parsed = http_parser_execute(&parser, &settings_null, &foo, 1); - if (parsed != 1) - goto err; - } - - parsed = http_parser_execute(&parser, &settings_null, buf1, buf1len); - if (parsed != buf1len) goto err; - return; - - err: - fprintf(stderr, - "\n*** error in test_no_overflow_long_body %s of length %lu ***\n", - req ? "REQUEST" : "RESPONSE", - (unsigned long)length); - abort(); -} - -void -test_multiple3 (const struct message *r1, const struct message *r2, const struct message *r3) -{ - int message_count = count_parsed_messages(3, r1, r2, r3); - - char total[ strlen(r1->raw) - + strlen(r2->raw) - + strlen(r3->raw) - + 1 - ]; - total[0] = '\0'; - - strcat(total, r1->raw); - strcat(total, r2->raw); - strcat(total, r3->raw); - - parser_init(r1->type); - - size_t read; - - read = parse(total, strlen(total)); - - if (parser->upgrade) { - upgrade_message_fix(total, read, 3, r1, r2, r3); - goto test; - } - - if (read != strlen(total)) { - print_error(total, read); - abort(); - } - - read = parse(NULL, 0); - - if (read != 0) { - print_error(total, read); - abort(); - } - -test: - - if (message_count != num_messages) { - fprintf(stderr, "\n\n*** Parser didn't see 3 messages only %d *** \n", num_messages); - abort(); - } - - if (!message_eq(0, r1)) abort(); - if (message_count > 1 && !message_eq(1, r2)) abort(); - if (message_count > 2 && !message_eq(2, r3)) abort(); - - parser_free(); -} - -/* SCAN through every possible breaking to make sure the - * parser can handle getting the content in any chunks that - * might come from the socket - */ -void -test_scan (const struct message *r1, const struct message *r2, const struct message *r3) -{ - char total[80*1024] = "\0"; - char buf1[80*1024] = "\0"; - char buf2[80*1024] = "\0"; - char buf3[80*1024] = "\0"; - - strcat(total, r1->raw); - strcat(total, r2->raw); - strcat(total, r3->raw); - - size_t read; - - int total_len = strlen(total); - - int total_ops = 2 * (total_len - 1) * (total_len - 2) / 2; - int ops = 0 ; - - size_t buf1_len, buf2_len, buf3_len; - int message_count = count_parsed_messages(3, r1, r2, r3); - - int i,j,type_both; - for (type_both = 0; type_both < 2; type_both ++ ) { - for (j = 2; j < total_len; j ++ ) { - for (i = 1; i < j; i ++ ) { - - if (ops % 1000 == 0) { - printf("\b\b\b\b%3.0f%%", 100 * (float)ops /(float)total_ops); - fflush(stdout); - } - ops += 1; - - parser_init(type_both ? HTTP_BOTH : r1->type); - - buf1_len = i; - strlncpy(buf1, sizeof(buf1), total, buf1_len); - buf1[buf1_len] = 0; - - buf2_len = j - i; - strlncpy(buf2, sizeof(buf1), total+i, buf2_len); - buf2[buf2_len] = 0; - - buf3_len = total_len - j; - strlncpy(buf3, sizeof(buf1), total+j, buf3_len); - buf3[buf3_len] = 0; - - read = parse(buf1, buf1_len); - - if (parser->upgrade) goto test; - - if (read != buf1_len) { - print_error(buf1, read); - goto error; - } - - read += parse(buf2, buf2_len); - - if (parser->upgrade) goto test; - - if (read != buf1_len + buf2_len) { - print_error(buf2, read); - goto error; - } - - read += parse(buf3, buf3_len); - - if (parser->upgrade) goto test; - - if (read != buf1_len + buf2_len + buf3_len) { - print_error(buf3, read); - goto error; - } - - parse(NULL, 0); - -test: - if (parser->upgrade) { - upgrade_message_fix(total, read, 3, r1, r2, r3); - } - - if (message_count != num_messages) { - fprintf(stderr, "\n\nParser didn't see %d messages only %d\n", - message_count, num_messages); - goto error; - } - - if (!message_eq(0, r1)) { - fprintf(stderr, "\n\nError matching messages[0] in test_scan.\n"); - goto error; - } - - if (message_count > 1 && !message_eq(1, r2)) { - fprintf(stderr, "\n\nError matching messages[1] in test_scan.\n"); - goto error; - } - - if (message_count > 2 && !message_eq(2, r3)) { - fprintf(stderr, "\n\nError matching messages[2] in test_scan.\n"); - goto error; - } - - parser_free(); - } - } - } - puts("\b\b\b\b100%"); - return; - - error: - fprintf(stderr, "i=%d j=%d\n", i, j); - fprintf(stderr, "buf1 (%u) %s\n\n", (unsigned int)buf1_len, buf1); - fprintf(stderr, "buf2 (%u) %s\n\n", (unsigned int)buf2_len , buf2); - fprintf(stderr, "buf3 (%u) %s\n", (unsigned int)buf3_len, buf3); - abort(); -} - -// user required to free the result -// string terminated by \0 -char * -create_large_chunked_message (int body_size_in_kb, const char* headers) -{ - int i; - size_t wrote = 0; - size_t headers_len = strlen(headers); - size_t bufsize = headers_len + (5+1024+2)*body_size_in_kb + 6; - char * buf = malloc(bufsize); - - memcpy(buf, headers, headers_len); - wrote += headers_len; - - for (i = 0; i < body_size_in_kb; i++) { - // write 1kb chunk into the body. - memcpy(buf + wrote, "400\r\n", 5); - wrote += 5; - memset(buf + wrote, 'C', 1024); - wrote += 1024; - strcpy(buf + wrote, "\r\n"); - wrote += 2; - } - - memcpy(buf + wrote, "0\r\n\r\n", 6); - wrote += 6; - assert(wrote == bufsize); - - return buf; -} - -void -test_status_complete (void) -{ - parser_init(HTTP_RESPONSE); - parser->data = 0; - http_parser_settings settings = settings_null; - settings.on_status_complete = status_complete_cb; - - char *response = "don't mind me, just a simple response"; - http_parser_execute(parser, &settings, response, strlen(response)); - assert(parser->data == (void*)0); // the status_complete callback was never called - assert(parser->http_errno == HPE_INVALID_CONSTANT); // the errno for an invalid status line -} - -/* Verify that we can pause parsing at any of the bytes in the - * message and still get the result that we're expecting. */ -void -test_message_pause (const struct message *msg) -{ - char *buf = (char*) msg->raw; - size_t buflen = strlen(msg->raw); - size_t nread; - - parser_init(msg->type); - - do { - nread = parse_pause(buf, buflen); - - // We can only set the upgrade buffer once we've gotten our message - // completion callback. - if (messages[0].message_complete_cb_called && - msg->upgrade && - parser->upgrade) { - messages[0].upgrade = buf + nread; - goto test; - } - - if (nread < buflen) { - - // Not much do to if we failed a strict-mode check - if (HTTP_PARSER_ERRNO(parser) == HPE_STRICT) { - parser_free(); - return; - } - - assert (HTTP_PARSER_ERRNO(parser) == HPE_PAUSED); - } - - buf += nread; - buflen -= nread; - http_parser_pause(parser, 0); - } while (buflen > 0); - - nread = parse_pause(NULL, 0); - assert (nread == 0); - -test: - if (num_messages != 1) { - printf("\n*** num_messages != 1 after testing '%s' ***\n\n", msg->name); - abort(); - } - - if(!message_eq(0, msg)) abort(); - - parser_free(); -} - -int -main (void) -{ - parser = NULL; - int i, j, k; - int request_count; - int response_count; - unsigned long version; - unsigned major; - unsigned minor; - unsigned patch; - - version = http_parser_version(); - major = (version >> 16) & 255; - minor = (version >> 8) & 255; - patch = version & 255; - printf("http_parser v%u.%u.%u (0x%06lx)\n", major, minor, patch, version); - - printf("sizeof(http_parser) = %u\n", (unsigned int)sizeof(http_parser)); - - for (request_count = 0; requests[request_count].name; request_count++); - for (response_count = 0; responses[response_count].name; response_count++); - - //// API - test_preserve_data(); - test_parse_url(); - test_method_str(); - - //// OVERFLOW CONDITIONS - - test_header_overflow_error(HTTP_REQUEST); - test_no_overflow_long_body(HTTP_REQUEST, 1000); - test_no_overflow_long_body(HTTP_REQUEST, 100000); - - test_header_overflow_error(HTTP_RESPONSE); - test_no_overflow_long_body(HTTP_RESPONSE, 1000); - test_no_overflow_long_body(HTTP_RESPONSE, 100000); - - test_header_content_length_overflow_error(); - test_chunk_content_length_overflow_error(); - - //// RESPONSES - - for (i = 0; i < response_count; i++) { - test_message(&responses[i]); - } - - for (i = 0; i < response_count; i++) { - test_message_pause(&responses[i]); - } - - for (i = 0; i < response_count; i++) { - if (!responses[i].should_keep_alive) continue; - for (j = 0; j < response_count; j++) { - if (!responses[j].should_keep_alive) continue; - for (k = 0; k < response_count; k++) { - test_multiple3(&responses[i], &responses[j], &responses[k]); - } - } - } - - test_message_count_body(&responses[NO_HEADERS_NO_BODY_404]); - test_message_count_body(&responses[TRAILING_SPACE_ON_CHUNKED_BODY]); - - // test very large chunked response - { - char * msg = create_large_chunked_message(31337, - "HTTP/1.0 200 OK\r\n" - "Transfer-Encoding: chunked\r\n" - "Content-Type: text/plain\r\n" - "\r\n"); - struct message large_chunked = - {.name= "large chunked" - ,.type= HTTP_RESPONSE - ,.raw= msg - ,.should_keep_alive= FALSE - ,.message_complete_on_eof= FALSE - ,.http_major= 1 - ,.http_minor= 0 - ,.status_code= 200 - ,.num_headers= 2 - ,.headers= - { { "Transfer-Encoding", "chunked" } - , { "Content-Type", "text/plain" } - } - ,.body_size= 31337*1024 - }; - test_message_count_body(&large_chunked); - free(msg); - } - - - - printf("response scan 1/2 "); - test_scan( &responses[TRAILING_SPACE_ON_CHUNKED_BODY] - , &responses[NO_BODY_HTTP10_KA_204] - , &responses[NO_REASON_PHRASE] - ); - - printf("response scan 2/2 "); - test_scan( &responses[BONJOUR_MADAME_FR] - , &responses[UNDERSTORE_HEADER_KEY] - , &responses[NO_CARRIAGE_RET] - ); - - puts("responses okay"); - - - /// REQUESTS - - test_simple("GET / HTP/1.1\r\n\r\n", HPE_INVALID_VERSION); - - // Well-formed but incomplete - test_simple("GET / HTTP/1.1\r\n" - "Content-Type: text/plain\r\n" - "Content-Length: 6\r\n" - "\r\n" - "fooba", - HPE_OK); - - static const char *all_methods[] = { - "DELETE", - "GET", - "HEAD", - "POST", - "PUT", - //"CONNECT", //CONNECT can't be tested like other methods, it's a tunnel - "OPTIONS", - "TRACE", - "COPY", - "LOCK", - "MKCOL", - "MOVE", - "PROPFIND", - "PROPPATCH", - "UNLOCK", - "REPORT", - "MKACTIVITY", - "CHECKOUT", - "MERGE", - "M-SEARCH", - "NOTIFY", - "SUBSCRIBE", - "UNSUBSCRIBE", - "PATCH", - 0 }; - const char **this_method; - for (this_method = all_methods; *this_method; this_method++) { - char buf[200]; - sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method); - test_simple(buf, HPE_OK); - } - - static const char *bad_methods[] = { - "ASDF", - "C******", - "COLA", - "GEM", - "GETA", - "M****", - "MKCOLA", - "PROPPATCHA", - "PUN", - "PX", - "SA", - "hello world", - 0 }; - for (this_method = bad_methods; *this_method; this_method++) { - char buf[200]; - sprintf(buf, "%s / HTTP/1.1\r\n\r\n", *this_method); - test_simple(buf, HPE_INVALID_METHOD); - } - - const char *dumbfuck2 = - "GET / HTTP/1.1\r\n" - "X-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n" - "\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n" - "\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n" - "\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n" - "\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n" - "\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n" - "\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n" - "\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n" - "\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n" - "\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n" - "\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n" - "\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n" - "\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n" - "\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgHTTPAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n" - "\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n" - "\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n" - "\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n" - "\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n" - "\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n" - "\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n" - "\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n" - "\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n" - "\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n" - "\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n" - "\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n" - "\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n" - "\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n" - "\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n" - "\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n" - "\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n" - "\tRA==\r\n" - "\t-----END CERTIFICATE-----\r\n" - "\r\n"; - test_simple(dumbfuck2, HPE_OK); - -#if 0 - // NOTE(Wed Nov 18 11:57:27 CET 2009) this seems okay. we just read body - // until EOF. - // - // no content-length - // error if there is a body without content length - const char *bad_get_no_headers_no_body = "GET /bad_get_no_headers_no_body/world HTTP/1.1\r\n" - "Accept: */*\r\n" - "\r\n" - "HELLO"; - test_simple(bad_get_no_headers_no_body, 0); -#endif - /* TODO sending junk and large headers gets rejected */ - - - /* check to make sure our predefined requests are okay */ - for (i = 0; requests[i].name; i++) { - test_message(&requests[i]); - } - - for (i = 0; i < request_count; i++) { - test_message_pause(&requests[i]); - } - - for (i = 0; i < request_count; i++) { - if (!requests[i].should_keep_alive) continue; - for (j = 0; j < request_count; j++) { - if (!requests[j].should_keep_alive) continue; - for (k = 0; k < request_count; k++) { - test_multiple3(&requests[i], &requests[j], &requests[k]); - } - } - } - - printf("request scan 1/4 "); - test_scan( &requests[GET_NO_HEADERS_NO_BODY] - , &requests[GET_ONE_HEADER_NO_BODY] - , &requests[GET_NO_HEADERS_NO_BODY] - ); - - printf("request scan 2/4 "); - test_scan( &requests[POST_CHUNKED_ALL_YOUR_BASE] - , &requests[POST_IDENTITY_BODY_WORLD] - , &requests[GET_FUNKY_CONTENT_LENGTH] - ); - - printf("request scan 3/4 "); - test_scan( &requests[TWO_CHUNKS_MULT_ZERO_END] - , &requests[CHUNKED_W_TRAILING_HEADERS] - , &requests[CHUNKED_W_BULLSHIT_AFTER_LENGTH] - ); - - printf("request scan 4/4 "); - test_scan( &requests[QUERY_URL_WITH_QUESTION_MARK_GET] - , &requests[PREFIX_NEWLINE_GET ] - , &requests[CONNECT_REQUEST] - ); - - test_status_complete(); - - puts("requests okay"); - - return 0; -} diff --git a/src/beast/modules/beast_core/beast_core.cpp b/src/beast/modules/beast_core/beast_core.cpp index 7658f795ea..8766591f71 100644 --- a/src/beast/modules/beast_core/beast_core.cpp +++ b/src/beast/modules/beast_core/beast_core.cpp @@ -180,7 +180,6 @@ namespace beast #include "network/MACAddress.cpp" #include "network/NamedPipe.cpp" #include "network/Socket.cpp" -#include "network/URL.cpp" #include "network/IPAddress.cpp" #include "streams/BufferedInputStream.cpp" @@ -193,11 +192,9 @@ namespace beast #include "system/SystemStats.cpp" -#include "text/CharacterFunctions.cpp" #include "text/LexicalCast.cpp" #include "text/Identifier.cpp" #include "text/LocalisedStrings.cpp" -#include "text/String.cpp" #include "text/StringArray.cpp" #include "text/StringPairArray.cpp" #include "text/StringPool.cpp" @@ -293,6 +290,17 @@ namespace beast } +// Has to be outside the beast namespace +extern "C" { +void beast_reportFatalError (char const* message, char const* fileName, int lineNumber) +{ + if (beast::beast_isRunningUnderDebugger()) + beast_breakDebugger; + beast::FatalError (message, fileName, lineNumber); + BEAST_ANALYZER_NORETURN +} +} + #ifdef _CRTDBG_MAP_ALLOC #pragma pop_macro("calloc") #pragma pop_macro("free") diff --git a/src/beast/modules/beast_core/beast_core.h b/src/beast/modules/beast_core/beast_core.h index b0fedbe090..16f9df5463 100644 --- a/src/beast/modules/beast_core/beast_core.h +++ b/src/beast/modules/beast_core/beast_core.h @@ -26,13 +26,11 @@ // TargetPlatform.h should not use anything from BeastConfig.h #include "../../beast/Config.h" -#include "system/BeastConfigCheck.h" +#include "../../beast/config/ContractChecks.h" # include "system/BeforeBoost.h" # include "system/BoostIncludes.h" #include "system/FunctionalIncludes.h" -#include "system/PlatformDefs.h" -#include "system/StandardHeader.h" #if BEAST_MSVC # pragma warning (disable: 4251) // (DLL build warning, must be disabled before pushing the warning state) @@ -43,6 +41,53 @@ # endif #endif +//------------------------------------------------------------------------------ + +// New header-only library modeled more closely according to boost +#include "../../beast/CStdInt.h" +#include "../../beast/StaticAssert.h" +#include "../../beast/Uncopyable.h" +#include "../../beast/Atomic.h" +#include "../../beast/Arithmetic.h" +#include "../../beast/ByteOrder.h" +#include "../../beast/HeapBlock.h" +#include "../../beast/Memory.h" +#include "../../beast/Intrusive.h" +#include "../../beast/Net.h" +#include "../../beast/Strings.h" +#include "../../beast/TypeTraits.h" +#include "../../beast/Thread.h" +#include "../../beast/Utility.h" + +#include "system/StandardIncludes.h" + +namespace beast { + +class InputStream; +class OutputStream; +class FileInputStream; +class FileOutputStream; + +// Order matters, since headers don't have their own #include lines. +// Add new includes to the bottom. + +#include "diagnostic/Throw.h" +#include "system/Functional.h" +#include "memory/AtomicCounter.h" +#include "memory/AtomicFlag.h" +#include "memory/AtomicPointer.h" +#include "memory/AtomicState.h" +#include "threads/SpinDelay.h" +#include "memory/StaticObject.h" + +#include "time/AtExitHook.h" +#include "diagnostic/LeakChecked.h" +#include "time/RelativeTime.h" +#include "time/Time.h" +#include "threads/ScopedLock.h" +#include "threads/CriticalSection.h" +#include "containers/ElementComparator.h" + // If the MSVC debug heap headers were included, disable // the macros during the juce include since they conflict. #ifdef _CRTDBG_MAP_ALLOC @@ -73,75 +118,25 @@ #undef _aligned_offset_recalloc #undef _aligned_msize #endif - -//------------------------------------------------------------------------------ - -namespace beast { -extern BEAST_API bool BEAST_CALLTYPE beast_isRunningUnderDebugger(); -extern BEAST_API void BEAST_CALLTYPE logAssertion (char const* file, int line) noexcept; -} - -// New header-only library modeled more closely according to boost -#include "../../beast/CStdInt.h" -#include "../../beast/StaticAssert.h" -#include "../../beast/Uncopyable.h" -#include "../../beast/Atomic.h" -#include "../../beast/Intrusive.h" -#include "../../beast/Net.h" -#include "../../beast/TypeTraits.h" -#include "../../beast/Thread.h" -#include "../../beast/Utility.h" - -namespace beast { - -class InputStream; -class OutputStream; -class FileInputStream; -class FileOutputStream; - -// Order matters, since headers don't have their own #include lines. -// Add new includes to the bottom. - -#include "diagnostic/ContractChecks.h" -#include "memory/Memory.h" -#include "maths/MathsFunctions.h" -#include "memory/ByteOrder.h" -#include "text/CharacterFunctions.h" - -#if BEAST_MSVC -# pragma warning (push) -# pragma warning (disable: 4514 4996) -#endif -#include "text/CharPointer_UTF8.h" -#include "text/CharPointer_UTF16.h" -#include "text/CharPointer_UTF32.h" -#include "text/CharPointer_ASCII.h" -#if BEAST_MSVC -# pragma warning (pop) -#endif - -#include "diagnostic/Throw.h" -#include "system/Functional.h" -#include "memory/AtomicCounter.h" -#include "memory/AtomicFlag.h" -#include "memory/AtomicPointer.h" -#include "memory/AtomicState.h" -#include "threads/SpinDelay.h" -#include "memory/StaticObject.h" - -#include "text/StringCharPointerType.h" -#include "text/StringFromNumber.h" -#include "text/String.h" -#include "time/AtExitHook.h" -#include "diagnostic/LeakChecked.h" -#include "time/RelativeTime.h" -#include "time/Time.h" -#include "memory/HeapBlock.h" -#include "threads/ScopedLock.h" -#include "threads/CriticalSection.h" -#include "containers/ElementComparator.h" #include "containers/ArrayAllocationBase.h" +#ifdef _CRTDBG_MAP_ALLOC +#pragma pop_macro("_aligned_msize") +#pragma pop_macro("_aligned_offset_recalloc") +#pragma pop_macro("_aligned_offset_realloc") +#pragma pop_macro("_aligned_recalloc") +#pragma pop_macro("_aligned_realloc") +#pragma pop_macro("_aligned_offset_malloc") +#pragma pop_macro("_aligned_malloc") +#pragma pop_macro("_aligned_free") +#pragma pop_macro("_recalloc") +#pragma pop_macro("realloc") +#pragma pop_macro("malloc") +#pragma pop_macro("free") +#pragma pop_macro("calloc") +#endif + #include "containers/Array.h" + #include "misc/Result.h" #include "text/StringArray.h" #include "memory/MemoryBlock.h" @@ -163,7 +158,6 @@ class FileOutputStream; #include "diagnostic/Debug.h" #include "text/LexicalCast.h" #include "memory/ContainerDeletePolicy.h" -#include "memory/ByteSwap.h" #include "maths/Math.h" #include "maths/uint24.h" #include "logging/Logger.h" @@ -200,7 +194,6 @@ class FileOutputStream; #include "files/FileInputStream.h" #include "streams/InputSource.h" #include "streams/FileInputSource.h" -#include "text/NewLine.h" #include "streams/OutputStream.h" #include "files/FileOutputStream.h" #include "files/FileSearchPath.h" @@ -212,10 +205,7 @@ class FileOutputStream; #include "logging/Logger.h" #include "maths/Expression.h" #include "maths/Interval.h" -#include "maths/MathsFunctions.h" #include "maths/MurmurHash.h" -#include "memory/ByteOrder.h" -#include "memory/Memory.h" #include "memory/OptionalScopedPointer.h" #include "memory/SharedSingleton.h" #include "memory/WeakReference.h" @@ -228,7 +218,6 @@ class FileOutputStream; #include "threads/ReadWriteLock.h" #include "network/NamedPipe.h" #include "network/Socket.h" -#include "network/URL.h" #include "streams/BufferedInputStream.h" #include "streams/MemoryInputStream.h" #include "streams/MemoryOutputStream.h" @@ -279,22 +268,6 @@ class FileOutputStream; } -#ifdef _CRTDBG_MAP_ALLOC -#pragma pop_macro("_aligned_msize") -#pragma pop_macro("_aligned_offset_recalloc") -#pragma pop_macro("_aligned_offset_realloc") -#pragma pop_macro("_aligned_recalloc") -#pragma pop_macro("_aligned_realloc") -#pragma pop_macro("_aligned_offset_malloc") -#pragma pop_macro("_aligned_malloc") -#pragma pop_macro("_aligned_free") -#pragma pop_macro("_recalloc") -#pragma pop_macro("realloc") -#pragma pop_macro("malloc") -#pragma pop_macro("free") -#pragma pop_macro("calloc") -#endif - #if BEAST_MSVC #pragma warning (pop) #endif diff --git a/src/beast/modules/beast_core/diagnostic/FatalError.cpp b/src/beast/modules/beast_core/diagnostic/FatalError.cpp index 4ad792b9ee..df21573531 100644 --- a/src/beast/modules/beast_core/diagnostic/FatalError.cpp +++ b/src/beast/modules/beast_core/diagnostic/FatalError.cpp @@ -107,14 +107,6 @@ FatalError::FatalError (char const* message, char const* fileName, int lineNumbe Process::terminate (); } -void reportFatalError (char const* message, char const* fileName, int lineNumber) -{ - if (beast::beast_isRunningUnderDebugger()) - beast_breakDebugger; - FatalError (message, fileName, lineNumber); - BEAST_ANALYZER_NORETURN -} - //------------------------------------------------------------------------------ // Yes even this class can have a unit test. It's manually triggered though. diff --git a/src/beast/modules/beast_core/diagnostic/FatalError.h b/src/beast/modules/beast_core/diagnostic/FatalError.h index fe25d51a37..861575b314 100644 --- a/src/beast/modules/beast_core/diagnostic/FatalError.h +++ b/src/beast/modules/beast_core/diagnostic/FatalError.h @@ -146,11 +146,4 @@ private: static Reporter* s_reporter; }; -//------------------------------------------------------------------------------ - -/** Report a fatal error message and terminate the application. - Normally you won't call this directly. -*/ -extern void reportFatalError (char const* message, char const* fileName, int lineNumber); - #endif diff --git a/src/beast/modules/beast_core/logging/Logger.cpp b/src/beast/modules/beast_core/logging/Logger.cpp index d8ac98e66d..06d252f42a 100644 --- a/src/beast/modules/beast_core/logging/Logger.cpp +++ b/src/beast/modules/beast_core/logging/Logger.cpp @@ -44,7 +44,7 @@ void Logger::writeToLog (const String& message) } #if BEAST_LOG_ASSERTIONS || BEAST_DEBUG -void BEAST_API BEAST_CALLTYPE logAssertion (const char* const filename, const int lineNum) noexcept +void logAssertion (const char* const filename, const int lineNum) noexcept { String m ("BEAST Assertion failure in "); m << File::createFileWithoutCheckingPath (filename).getFileName() << ':' << lineNum; diff --git a/src/beast/modules/beast_core/logging/Logger.h b/src/beast/modules/beast_core/logging/Logger.h index f7336c4e0b..a9935d5f77 100644 --- a/src/beast/modules/beast_core/logging/Logger.h +++ b/src/beast/modules/beast_core/logging/Logger.h @@ -69,7 +69,7 @@ public: /** Writes a message to the standard error stream. This can be called directly, or by using the DBG() macro in - PlatformDefs.h (which will avoid calling the method in non-debug builds). + CompilerConfig.h (which will avoid calling the method in non-debug builds). */ static void BEAST_CALLTYPE outputDebugString (const String& text); diff --git a/src/beast/modules/beast_core/memory/ByteSwap.h b/src/beast/modules/beast_core/memory/ByteSwap.h deleted file mode 100644 index 94384eacd2..0000000000 --- a/src/beast/modules/beast_core/memory/ByteSwap.h +++ /dev/null @@ -1,126 +0,0 @@ -//------------------------------------------------------------------------------ -/* - This file is part of Beast: https://github.com/vinniefalco/Beast - Copyright 2013, Vinnie Falco - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ -//============================================================================== - -#ifndef BEAST_BYTESWAP_H_INCLUDED -#define BEAST_BYTESWAP_H_INCLUDED - -namespace detail -{ - -/** Specialized helper class template for swapping bytes. - - Normally you won't use this directly, use the helper function - byteSwap instead. You can specialize this class for your - own user defined types, as was done for uint24. - - @see swapBytes, uint24 -*/ -template -struct SwapBytes -{ - inline IntegralType operator() (IntegralType value) const noexcept - { - return ByteOrder::swap (value); - } -}; - -// Specializations for signed integers - -template <> -struct SwapBytes -{ - inline int16 operator() (int16 value) const noexcept - { - return static_cast (ByteOrder::swap (static_cast (value))); - } -}; - -template <> -struct SwapBytes -{ - inline int32 operator() (int32 value) const noexcept - { - return static_cast (ByteOrder::swap (static_cast (value))); - } -}; - -template <> -struct SwapBytes -{ - inline int64 operator() (int64 value) const noexcept - { - return static_cast (ByteOrder::swap (static_cast (value))); - } -}; - -} - -//------------------------------------------------------------------------------ - -/** Returns a type with the bytes swapped. - Little endian becomes big endian and vice versa. The underlying - type must be an integral type or behave like one. -*/ -template -inline IntegralType swapBytes (IntegralType value) noexcept -{ - return detail::SwapBytes () (value); -} - -/** Returns the machine byte-order value to little-endian byte order. */ -template -inline IntegralType toLittleEndian (IntegralType value) noexcept -{ -#if BEAST_LITTLE_ENDIAN - return value; -#else - return swapBytes (value); -#endif -} - -/** Returns the machine byte-order value to big-endian byte order. */ -template -inline IntegralType toBigEndian (IntegralType value) noexcept -{ -#if BEAST_LITTLE_ENDIAN - return swapBytes (value); -#else - return value; -#endif -} - -/** Returns the machine byte-order value to network byte order. */ -template -inline IntegralType toNetworkByteOrder (IntegralType value) noexcept -{ - return toBigEndian (value); -} - -/** Converts from network byte order to machine byte order. */ -template -inline IntegralType fromNetworkByteOrder (IntegralType value) noexcept -{ -#if BEAST_LITTLE_ENDIAN - return swapBytes (value); -#else - return value; -#endif -} - -#endif diff --git a/src/beast/modules/beast_core/native/android_Network.cpp b/src/beast/modules/beast_core/native/android_Network.cpp index 86ea9596b2..ec2ba4964e 100644 --- a/src/beast/modules/beast_core/native/android_Network.cpp +++ b/src/beast/modules/beast_core/native/android_Network.cpp @@ -57,114 +57,3 @@ bool Process::openEmailWithAttachments (const String& targetEmailAddress, // TODO return false; } - - -//============================================================================== -class WebInputStream - : public InputStream - , LeakChecked -{ -public: - //============================================================================== - WebInputStream (String address, bool isPost, const MemoryBlock& postData, - URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, - const String& headers, int timeOutMs, StringPairArray* responseHeaders) - { - if (! address.contains ("://")) - address = "http://" + address; - - JNIEnv* env = getEnv(); - - jbyteArray postDataArray = 0; - - if (postData.getSize() > 0) - { - postDataArray = env->NewByteArray (postData.getSize()); - env->SetByteArrayRegion (postDataArray, 0, postData.getSize(), (const jbyte*) postData.getData()); - } - - LocalRef responseHeaderBuffer (env->NewObject (StringBuffer, StringBuffer.constructor)); - - stream = GlobalRef (env->CallStaticObjectMethod (BeastAppActivity, - BeastAppActivity.createHTTPStream, - javaString (address).get(), - (jboolean) isPost, - postDataArray, - javaString (headers).get(), - (jint) timeOutMs, - responseHeaderBuffer.get())); - - if (postDataArray != 0) - env->DeleteLocalRef (postDataArray); - - if (stream != 0) - { - StringArray headerLines; - - { - LocalRef headersString ((jstring) env->CallObjectMethod (responseHeaderBuffer.get(), - StringBuffer.toString)); - headerLines.addLines (beastString (env, headersString)); - } - - if (responseHeaders != 0) - { - for (int i = 0; i < headerLines.size(); ++i) - { - const String& header = headerLines[i]; - const String key (header.upToFirstOccurrenceOf (": ", false, false)); - const String value (header.fromFirstOccurrenceOf (": ", false, false)); - const String previousValue ((*responseHeaders) [key]); - - responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value)); - } - } - } - } - - ~WebInputStream() - { - if (stream != 0) - stream.callVoidMethod (HTTPStream.release); - } - - //============================================================================== - bool isExhausted() { return stream != nullptr && stream.callBooleanMethod (HTTPStream.isExhausted); } - int64 getTotalLength() { return stream != nullptr ? stream.callLongMethod (HTTPStream.getTotalLength) : 0; } - int64 getPosition() { return stream != nullptr ? stream.callLongMethod (HTTPStream.getPosition) : 0; } - bool setPosition (int64 wantedPos) { return stream != nullptr && stream.callBooleanMethod (HTTPStream.setPosition, (jlong) wantedPos); } - - int read (void* buffer, int bytesToRead) - { - bassert (buffer != nullptr && bytesToRead >= 0); - - if (stream == nullptr) - return 0; - - JNIEnv* env = getEnv(); - - jbyteArray javaArray = env->NewByteArray (bytesToRead); - - int numBytes = stream.callIntMethod (HTTPStream.read, javaArray, (jint) bytesToRead); - - if (numBytes > 0) - env->GetByteArrayRegion (javaArray, 0, numBytes, static_cast (buffer)); - - env->DeleteLocalRef (javaArray); - return numBytes; - } - - //============================================================================== - GlobalRef stream; -}; - -InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData, - OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, - const String& headers, const int timeOutMs, StringPairArray* responseHeaders) -{ - ScopedPointer wi (new WebInputStream (address, isPost, postData, - progressCallback, progressCallbackContext, - headers, timeOutMs, responseHeaders)); - - return wi->stream != 0 ? wi.release() : nullptr; -} diff --git a/src/beast/modules/beast_core/native/android_Threads.cpp b/src/beast/modules/beast_core/native/android_Threads.cpp index fe0e7aaf9b..e36cdf8252 100644 --- a/src/beast/modules/beast_core/native/android_Threads.cpp +++ b/src/beast/modules/beast_core/native/android_Threads.cpp @@ -57,7 +57,7 @@ void Process::setPriority (ProcessPriority prior) pthread_setschedparam (pthread_self(), policy, ¶m); } -BEAST_API bool BEAST_CALLTYPE beast_isRunningUnderDebugger() +bool beast_isRunningUnderDebugger() { return false; } diff --git a/src/beast/modules/beast_core/native/bsd_Network.cpp b/src/beast/modules/beast_core/native/bsd_Network.cpp index 45167cd463..9fb630149d 100644 --- a/src/beast/modules/beast_core/native/bsd_Network.cpp +++ b/src/beast/modules/beast_core/native/bsd_Network.cpp @@ -57,399 +57,3 @@ bool Process::openEmailWithAttachments (const String& /* targetEmailAddress */, return false; } - - -//============================================================================== -class WebInputStream - : public InputStream - , LeakChecked -{ -public: - WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_, - URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, - const String& headers_, int timeOutMs_, StringPairArray* responseHeaders) - : socketHandle (-1), levelsOfRedirection (0), - address (address_), headers (headers_), postData (postData_), position (0), - finished (false), isPost (isPost_), timeOutMs (timeOutMs_) - { - createConnection (progressCallback, progressCallbackContext); - - if (responseHeaders != nullptr && ! isError()) - { - for (int i = 0; i < headerLines.size(); ++i) - { - const String& headersEntry = headerLines[i]; - const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false)); - const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false)); - const String previousValue ((*responseHeaders) [key]); - responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value)); - } - } - } - - ~WebInputStream() - { - closeSocket(); - } - - //============================================================================== - bool isError() const { return socketHandle < 0; } - bool isExhausted() { return finished; } - int64 getPosition() { return position; } - - int64 getTotalLength() - { - //xxx to do - return -1; - } - - int read (void* buffer, int bytesToRead) - { - if (finished || isError()) - return 0; - - fd_set readbits; - FD_ZERO (&readbits); - FD_SET (socketHandle, &readbits); - - struct timeval tv; - tv.tv_sec = bmax (1, timeOutMs / 1000); - tv.tv_usec = 0; - - if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0) - return 0; // (timeout) - - const int bytesRead = bmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL)); - if (bytesRead == 0) - finished = true; - position += bytesRead; - return bytesRead; - } - - bool setPosition (int64 wantedPos) - { - if (isError()) - return false; - - if (wantedPos != position) - { - finished = false; - - if (wantedPos < position) - { - closeSocket(); - position = 0; - createConnection (0, 0); - } - - skipNextBytes (wantedPos - position); - } - - return true; - } - - //============================================================================== -private: - int socketHandle, levelsOfRedirection; - StringArray headerLines; - String address, headers; - MemoryBlock postData; - int64 position; - bool finished; - const bool isPost; - const int timeOutMs; - - void closeSocket() - { - if (socketHandle >= 0) - close (socketHandle); - - socketHandle = -1; - levelsOfRedirection = 0; - } - - void createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext) - { - closeSocket(); - - uint32 timeOutTime = Time::getMillisecondCounter(); - - if (timeOutMs == 0) - timeOutTime += 60000; - else if (timeOutMs < 0) - timeOutTime = 0xffffffff; - else - timeOutTime += timeOutMs; - - String hostName, hostPath; - int hostPort; - if (! decomposeURL (address, hostName, hostPath, hostPort)) - return; - - String serverName, proxyName, proxyPath; - int proxyPort = 0; - int port = 0; - - const String proxyURL (getenv ("http_proxy")); - if (proxyURL.startsWithIgnoreCase ("http://")) - { - if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort)) - return; - - serverName = proxyName; - port = proxyPort; - } - else - { - serverName = hostName; - port = hostPort; - } - - struct addrinfo hints; - zerostruct (hints); - - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_NUMERICSERV; - - struct addrinfo* result = nullptr; - if (getaddrinfo (serverName.toUTF8(), String (port).toUTF8(), &hints, &result) != 0 || result == 0) - return; - - socketHandle = socket (result->ai_family, result->ai_socktype, 0); - - if (socketHandle == -1) - { - freeaddrinfo (result); - return; - } - - int receiveBufferSize = 16384; - setsockopt (socketHandle, SOL_SOCKET, SO_RCVBUF, (char*) &receiveBufferSize, sizeof (receiveBufferSize)); - setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, 0, 0); - - #if BEAST_MAC - setsockopt (socketHandle, SOL_SOCKET, SO_NOSIGPIPE, 0, 0); - #endif - - if (connect (socketHandle, result->ai_addr, result->ai_addrlen) == -1) - { - closeSocket(); - freeaddrinfo (result); - return; - } - - freeaddrinfo (result); - - { - const MemoryBlock requestHeader (createRequestHeader (hostName, hostPort, proxyName, proxyPort, - hostPath, address, headers, postData, isPost)); - - if (! sendHeader (socketHandle, requestHeader, timeOutTime, progressCallback, progressCallbackContext)) - { - closeSocket(); - return; - } - } - - String responseHeader (readResponse (socketHandle, timeOutTime)); - - if (responseHeader.isNotEmpty()) - { - headerLines = StringArray::fromLines (responseHeader); - - const int statusCode = responseHeader.fromFirstOccurrenceOf (" ", false, false) - .substring (0, 3).getIntValue(); - - //int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue(); - //bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked"); - - String location (findHeaderItem (headerLines, "Location:")); - - if (statusCode >= 300 && statusCode < 400 && location.isNotEmpty()) - { - if (! location.startsWithIgnoreCase ("http://")) - location = "http://" + location; - - if (++levelsOfRedirection <= 3) - { - address = location; - createConnection (progressCallback, progressCallbackContext); - return; - } - } - else - { - levelsOfRedirection = 0; - return; - } - } - - closeSocket(); - } - - //============================================================================== - static String readResponse (const int socketHandle, const uint32 timeOutTime) - { - int bytesRead = 0, numConsecutiveLFs = 0; - MemoryBlock buffer (1024, true); - - while (numConsecutiveLFs < 2 && bytesRead < 32768 - && Time::getMillisecondCounter() <= timeOutTime) - { - fd_set readbits; - FD_ZERO (&readbits); - FD_SET (socketHandle, &readbits); - - struct timeval tv; - tv.tv_sec = bmax (1, (int) (timeOutTime - Time::getMillisecondCounter()) / 1000); - tv.tv_usec = 0; - - if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0) - return String::empty; // (timeout) - - buffer.ensureSize (bytesRead + 8, true); - char* const dest = (char*) buffer.getData() + bytesRead; - - if (recv (socketHandle, dest, 1, 0) == -1) - return String::empty; - - const char lastByte = *dest; - ++bytesRead; - - if (lastByte == '\n') - ++numConsecutiveLFs; - else if (lastByte != '\r') - numConsecutiveLFs = 0; - } - - const String header (CharPointer_UTF8 ((const char*) buffer.getData())); - - if (header.startsWithIgnoreCase ("HTTP/")) - return header.trimEnd(); - - return String::empty; - } - - static void writeValueIfNotPresent (MemoryOutputStream& dest, const String& headers, const String& key, const String& value) - { - if (! headers.containsIgnoreCase (key)) - dest << "\r\n" << key << ' ' << value; - } - - static void writeHost (MemoryOutputStream& dest, const bool isPost, const String& path, const String& host, const int port) - { - dest << (isPost ? "POST " : "GET ") << path << " HTTP/1.0\r\nHost: " << host; - - if (port > 0) - dest << ':' << port; - } - - static MemoryBlock createRequestHeader (const String& hostName, const int hostPort, - const String& proxyName, const int proxyPort, - const String& hostPath, const String& originalURL, - const String& userHeaders, const MemoryBlock& postData, - const bool isPost) - { - MemoryOutputStream header; - - if (proxyName.isEmpty()) - writeHost (header, isPost, hostPath, hostName, hostPort); - else - writeHost (header, isPost, originalURL, proxyName, proxyPort); - - writeValueIfNotPresent (header, userHeaders, "User-Agent:", "BEAST/" BEAST_STRINGIFY(BEAST_MAJOR_VERSION) - "." BEAST_STRINGIFY(BEAST_MINOR_VERSION) - "." BEAST_STRINGIFY(BEAST_BUILDNUMBER)); - writeValueIfNotPresent (header, userHeaders, "Connection:", "Close"); - - if (isPost) - writeValueIfNotPresent (header, userHeaders, "Content-Length:", String ((int) postData.getSize())); - - header << "\r\n" << userHeaders - << "\r\n" << postData; - - return header.getMemoryBlock(); - } - - static bool sendHeader (int socketHandle, const MemoryBlock& requestHeader, const uint32 timeOutTime, - URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext) - { - size_t totalHeaderSent = 0; - - while (totalHeaderSent < requestHeader.getSize()) - { - if (Time::getMillisecondCounter() > timeOutTime) - return false; - - const int numToSend = bmin (1024, (int) (requestHeader.getSize() - totalHeaderSent)); - - if (send (socketHandle, static_cast (requestHeader.getData()) + totalHeaderSent, numToSend, 0) != numToSend) - return false; - - totalHeaderSent += numToSend; - - if (progressCallback != nullptr && ! progressCallback (progressCallbackContext, totalHeaderSent, requestHeader.getSize())) - return false; - } - - return true; - } - - static bool decomposeURL (const String& url, String& host, String& path, int& port) - { - if (! url.startsWithIgnoreCase ("http://")) - return false; - - const int nextSlash = url.indexOfChar (7, '/'); - int nextColon = url.indexOfChar (7, ':'); - if (nextColon > nextSlash && nextSlash > 0) - nextColon = -1; - - if (nextColon >= 0) - { - host = url.substring (7, nextColon); - - if (nextSlash >= 0) - port = url.substring (nextColon + 1, nextSlash).getIntValue(); - else - port = url.substring (nextColon + 1).getIntValue(); - } - else - { - port = 80; - - if (nextSlash >= 0) - host = url.substring (7, nextSlash); - else - host = url.substring (7); - } - - if (nextSlash >= 0) - path = url.substring (nextSlash); - else - path = "/"; - - return true; - } - - static String findHeaderItem (const StringArray& lines, const String& itemName) - { - for (int i = 0; i < lines.size(); ++i) - if (lines[i].startsWithIgnoreCase (itemName)) - return lines[i].substring (itemName.length()).trim(); - - return String::empty; - } -}; - -InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData, - OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, - const String& headers, const int timeOutMs, StringPairArray* responseHeaders) -{ - ScopedPointer wi (new WebInputStream (address, isPost, postData, - progressCallback, progressCallbackContext, - headers, timeOutMs, responseHeaders)); - - return wi->isError() ? nullptr : wi.release(); -} diff --git a/src/beast/modules/beast_core/native/bsd_Threads.cpp b/src/beast/modules/beast_core/native/bsd_Threads.cpp index c6160ca056..03622e9cc9 100644 --- a/src/beast/modules/beast_core/native/bsd_Threads.cpp +++ b/src/beast/modules/beast_core/native/bsd_Threads.cpp @@ -47,7 +47,7 @@ void Process::setPriority (const ProcessPriority prior) pthread_setschedparam (pthread_self(), policy, ¶m); } -BEAST_API bool BEAST_CALLTYPE beast_isRunningUnderDebugger() +bool beast_isRunningUnderDebugger() { // XXX not implemented for FreeBSD! bassertfalse; diff --git a/src/beast/modules/beast_core/native/linux_Files.cpp b/src/beast/modules/beast_core/native/linux_Files.cpp index e2370c91e3..3a9aa88cf3 100644 --- a/src/beast/modules/beast_core/native/linux_Files.cpp +++ b/src/beast/modules/beast_core/native/linux_Files.cpp @@ -329,9 +329,7 @@ bool Process::openDocument (const String& fileName, const String& parameters) String cmdString (fileName.replace (" ", "\\ ",false)); cmdString << " " << parameters; - if (URL::isProbablyAWebsiteURL (fileName) - || cmdString.startsWithIgnoreCase ("file:") - || URL::isProbablyAnEmailAddress (fileName) + if ( cmdString.startsWithIgnoreCase ("file:") || File::createFileWithoutCheckingPath (fileName).isDirectory() || ! isFileExecutable (fileName)) { diff --git a/src/beast/modules/beast_core/native/linux_Network.cpp b/src/beast/modules/beast_core/native/linux_Network.cpp index 137718093c..38046c496d 100644 --- a/src/beast/modules/beast_core/native/linux_Network.cpp +++ b/src/beast/modules/beast_core/native/linux_Network.cpp @@ -59,399 +59,3 @@ bool Process::openEmailWithAttachments (const String& /* targetEmailAddress */, return false; } - - -//============================================================================== -class WebInputStream - : public InputStream - , LeakChecked -{ -public: - WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_, - URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, - const String& headers_, int timeOutMs_, StringPairArray* responseHeaders) - : socketHandle (-1), levelsOfRedirection (0), - address (address_), headers (headers_), postData (postData_), position (0), - finished (false), isPost (isPost_), timeOutMs (timeOutMs_) - { - createConnection (progressCallback, progressCallbackContext); - - if (responseHeaders != nullptr && ! isError()) - { - for (int i = 0; i < headerLines.size(); ++i) - { - const String& headersEntry = headerLines[i]; - const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false)); - const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false)); - const String previousValue ((*responseHeaders) [key]); - responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value)); - } - } - } - - ~WebInputStream() - { - closeSocket(); - } - - //============================================================================== - bool isError() const { return socketHandle < 0; } - bool isExhausted() { return finished; } - int64 getPosition() { return position; } - - int64 getTotalLength() - { - //xxx to do - return -1; - } - - int read (void* buffer, int bytesToRead) - { - if (finished || isError()) - return 0; - - fd_set readbits; - FD_ZERO (&readbits); - FD_SET (socketHandle, &readbits); - - struct timeval tv; - tv.tv_sec = bmax (1, timeOutMs / 1000); - tv.tv_usec = 0; - - if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0) - return 0; // (timeout) - - const int bytesRead = bmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL)); - if (bytesRead == 0) - finished = true; - position += bytesRead; - return bytesRead; - } - - bool setPosition (int64 wantedPos) - { - if (isError()) - return false; - - if (wantedPos != position) - { - finished = false; - - if (wantedPos < position) - { - closeSocket(); - position = 0; - createConnection (0, 0); - } - - skipNextBytes (wantedPos - position); - } - - return true; - } - - //============================================================================== -private: - int socketHandle, levelsOfRedirection; - StringArray headerLines; - String address, headers; - MemoryBlock postData; - int64 position; - bool finished; - const bool isPost; - const int timeOutMs; - - void closeSocket() - { - if (socketHandle >= 0) - close (socketHandle); - - socketHandle = -1; - levelsOfRedirection = 0; - } - - void createConnection (URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext) - { - closeSocket(); - - uint32 timeOutTime = Time::getMillisecondCounter(); - - if (timeOutMs == 0) - timeOutTime += 60000; - else if (timeOutMs < 0) - timeOutTime = 0xffffffff; - else - timeOutTime += timeOutMs; - - String hostName, hostPath; - int hostPort; - if (! decomposeURL (address, hostName, hostPath, hostPort)) - return; - - String serverName, proxyName, proxyPath; - int proxyPort = 0; - int port = 0; - - const String proxyURL (getenv ("http_proxy")); - if (proxyURL.startsWithIgnoreCase ("http://")) - { - if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort)) - return; - - serverName = proxyName; - port = proxyPort; - } - else - { - serverName = hostName; - port = hostPort; - } - - struct addrinfo hints; - zerostruct (hints); - - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_NUMERICSERV; - - struct addrinfo* result = nullptr; - if (getaddrinfo (serverName.toUTF8(), String (port).toUTF8(), &hints, &result) != 0 || result == 0) - return; - - socketHandle = socket (result->ai_family, result->ai_socktype, 0); - - if (socketHandle == -1) - { - freeaddrinfo (result); - return; - } - - int receiveBufferSize = 16384; - setsockopt (socketHandle, SOL_SOCKET, SO_RCVBUF, (char*) &receiveBufferSize, sizeof (receiveBufferSize)); - setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, 0, 0); - - #if BEAST_MAC - setsockopt (socketHandle, SOL_SOCKET, SO_NOSIGPIPE, 0, 0); - #endif - - if (connect (socketHandle, result->ai_addr, result->ai_addrlen) == -1) - { - closeSocket(); - freeaddrinfo (result); - return; - } - - freeaddrinfo (result); - - { - const MemoryBlock requestHeader (createRequestHeader (hostName, hostPort, proxyName, proxyPort, - hostPath, address, headers, postData, isPost)); - - if (! sendHeader (socketHandle, requestHeader, timeOutTime, progressCallback, progressCallbackContext)) - { - closeSocket(); - return; - } - } - - String responseHeader (readResponse (socketHandle, timeOutTime)); - - if (responseHeader.isNotEmpty()) - { - headerLines = StringArray::fromLines (responseHeader); - - const int statusCode = responseHeader.fromFirstOccurrenceOf (" ", false, false) - .substring (0, 3).getIntValue(); - - //int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue(); - //bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked"); - - String location (findHeaderItem (headerLines, "Location:")); - - if (statusCode >= 300 && statusCode < 400 && location.isNotEmpty()) - { - if (! location.startsWithIgnoreCase ("http://")) - location = "http://" + location; - - if (++levelsOfRedirection <= 3) - { - address = location; - createConnection (progressCallback, progressCallbackContext); - return; - } - } - else - { - levelsOfRedirection = 0; - return; - } - } - - closeSocket(); - } - - //============================================================================== - static String readResponse (const int socketHandle, const uint32 timeOutTime) - { - int bytesRead = 0, numConsecutiveLFs = 0; - MemoryBlock buffer (1024, true); - - while (numConsecutiveLFs < 2 && bytesRead < 32768 - && Time::getMillisecondCounter() <= timeOutTime) - { - fd_set readbits; - FD_ZERO (&readbits); - FD_SET (socketHandle, &readbits); - - struct timeval tv; - tv.tv_sec = bmax (1, (int) (timeOutTime - Time::getMillisecondCounter()) / 1000); - tv.tv_usec = 0; - - if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0) - return String::empty; // (timeout) - - buffer.ensureSize (bytesRead + 8, true); - char* const dest = (char*) buffer.getData() + bytesRead; - - if (recv (socketHandle, dest, 1, 0) == -1) - return String::empty; - - const char lastByte = *dest; - ++bytesRead; - - if (lastByte == '\n') - ++numConsecutiveLFs; - else if (lastByte != '\r') - numConsecutiveLFs = 0; - } - - const String header (CharPointer_UTF8 ((const char*) buffer.getData())); - - if (header.startsWithIgnoreCase ("HTTP/")) - return header.trimEnd(); - - return String::empty; - } - - static void writeValueIfNotPresent (MemoryOutputStream& dest, const String& headers, const String& key, const String& value) - { - if (! headers.containsIgnoreCase (key)) - dest << "\r\n" << key << ' ' << value; - } - - static void writeHost (MemoryOutputStream& dest, const bool isPost, const String& path, const String& host, const int port) - { - dest << (isPost ? "POST " : "GET ") << path << " HTTP/1.0\r\nHost: " << host; - - if (port > 0) - dest << ':' << port; - } - - static MemoryBlock createRequestHeader (const String& hostName, const int hostPort, - const String& proxyName, const int proxyPort, - const String& hostPath, const String& originalURL, - const String& userHeaders, const MemoryBlock& postData, - const bool isPost) - { - MemoryOutputStream header; - - if (proxyName.isEmpty()) - writeHost (header, isPost, hostPath, hostName, hostPort); - else - writeHost (header, isPost, originalURL, proxyName, proxyPort); - - writeValueIfNotPresent (header, userHeaders, "User-Agent:", "BEAST/" BEAST_STRINGIFY(BEAST_MAJOR_VERSION) - "." BEAST_STRINGIFY(BEAST_MINOR_VERSION) - "." BEAST_STRINGIFY(BEAST_BUILDNUMBER)); - writeValueIfNotPresent (header, userHeaders, "Connection:", "Close"); - - if (isPost) - writeValueIfNotPresent (header, userHeaders, "Content-Length:", String ((int) postData.getSize())); - - header << "\r\n" << userHeaders - << "\r\n" << postData; - - return header.getMemoryBlock(); - } - - static bool sendHeader (int socketHandle, const MemoryBlock& requestHeader, const uint32 timeOutTime, - URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext) - { - size_t totalHeaderSent = 0; - - while (totalHeaderSent < requestHeader.getSize()) - { - if (Time::getMillisecondCounter() > timeOutTime) - return false; - - const int numToSend = bmin (1024, (int) (requestHeader.getSize() - totalHeaderSent)); - - if (send (socketHandle, static_cast (requestHeader.getData()) + totalHeaderSent, numToSend, 0) != numToSend) - return false; - - totalHeaderSent += numToSend; - - if (progressCallback != nullptr && ! progressCallback (progressCallbackContext, totalHeaderSent, requestHeader.getSize())) - return false; - } - - return true; - } - - static bool decomposeURL (const String& url, String& host, String& path, int& port) - { - if (! url.startsWithIgnoreCase ("http://")) - return false; - - const int nextSlash = url.indexOfChar (7, '/'); - int nextColon = url.indexOfChar (7, ':'); - if (nextColon > nextSlash && nextSlash > 0) - nextColon = -1; - - if (nextColon >= 0) - { - host = url.substring (7, nextColon); - - if (nextSlash >= 0) - port = url.substring (nextColon + 1, nextSlash).getIntValue(); - else - port = url.substring (nextColon + 1).getIntValue(); - } - else - { - port = 80; - - if (nextSlash >= 0) - host = url.substring (7, nextSlash); - else - host = url.substring (7); - } - - if (nextSlash >= 0) - path = url.substring (nextSlash); - else - path = "/"; - - return true; - } - - static String findHeaderItem (const StringArray& lines, const String& itemName) - { - for (int i = 0; i < lines.size(); ++i) - if (lines[i].startsWithIgnoreCase (itemName)) - return lines[i].substring (itemName.length()).trim(); - - return String::empty; - } -}; - -InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData, - OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, - const String& headers, const int timeOutMs, StringPairArray* responseHeaders) -{ - ScopedPointer wi (new WebInputStream (address, isPost, postData, - progressCallback, progressCallbackContext, - headers, timeOutMs, responseHeaders)); - - return wi->isError() ? nullptr : wi.release(); -} diff --git a/src/beast/modules/beast_core/native/linux_Threads.cpp b/src/beast/modules/beast_core/native/linux_Threads.cpp index 9dafe89df4..795bebc047 100644 --- a/src/beast/modules/beast_core/native/linux_Threads.cpp +++ b/src/beast/modules/beast_core/native/linux_Threads.cpp @@ -47,7 +47,7 @@ void Process::setPriority (const ProcessPriority prior) pthread_setschedparam (pthread_self(), policy, ¶m); } -BEAST_API bool BEAST_CALLTYPE beast_isRunningUnderDebugger() +bool beast_isRunningUnderDebugger() { static char testResult = 0; diff --git a/src/beast/modules/beast_core/native/mac_Network.mm b/src/beast/modules/beast_core/native/mac_Network.mm index c549b5d443..2d40d49808 100644 --- a/src/beast/modules/beast_core/native/mac_Network.mm +++ b/src/beast/modules/beast_core/native/mac_Network.mm @@ -294,135 +294,3 @@ private: } }; }; - - -//============================================================================== -class WebInputStream - : public InputStream - , LeakChecked -{ -public: - WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_, - URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, - const String& headers_, int timeOutMs_, StringPairArray* responseHeaders) - : address (address_), headers (headers_), postData (postData_), position (0), - finished (false), isPost (isPost_), timeOutMs (timeOutMs_) - { - BEAST_AUTORELEASEPOOL - { - createConnection (progressCallback, progressCallbackContext); - - if (responseHeaders != nullptr && connection != nullptr && connection->headers != nil) - { - NSEnumerator* enumerator = [connection->headers keyEnumerator]; - NSString* key; - - while ((key = [enumerator nextObject]) != nil) - responseHeaders->set (nsStringToBeast (key), - nsStringToBeast ((NSString*) [connection->headers objectForKey: key])); - } - } - } - - //============================================================================== - bool isError() const { return connection == nullptr; } - int64 getTotalLength() { return connection == nullptr ? -1 : connection->contentLength; } - bool isExhausted() { return finished; } - int64 getPosition() { return position; } - - int read (void* buffer, int bytesToRead) - { - bassert (buffer != nullptr && bytesToRead >= 0); - - if (finished || isError()) - return 0; - - BEAST_AUTORELEASEPOOL - { - const int bytesRead = connection->read (static_cast (buffer), bytesToRead); - position += bytesRead; - - if (bytesRead == 0) - finished = true; - - return bytesRead; - } - } - - bool setPosition (int64 wantedPos) - { - if (wantedPos != position) - { - finished = false; - - if (wantedPos < position) - { - connection = nullptr; - position = 0; - createConnection (0, 0); - } - - skipNextBytes (wantedPos - position); - } - - return true; - } - -private: - ScopedPointer connection; - String address, headers; - MemoryBlock postData; - int64 position; - bool finished; - const bool isPost; - const int timeOutMs; - - void createConnection (URL::OpenStreamProgressCallback* progressCallback, - void* progressCallbackContext) - { - bassert (connection == nullptr); - - NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL: [NSURL URLWithString: beastStringToNS (address)] - cachePolicy: NSURLRequestReloadIgnoringLocalCacheData - timeoutInterval: timeOutMs <= 0 ? 60.0 : (timeOutMs / 1000.0)]; - - if (req != nil) - { - [req setHTTPMethod: nsStringLiteral (isPost ? "POST" : "GET")]; - //[req setCachePolicy: NSURLRequestReloadIgnoringLocalAndRemoteCacheData]; - - StringArray headerLines; - headerLines.addLines (headers); - headerLines.removeEmptyStrings (true); - - for (int i = 0; i < headerLines.size(); ++i) - { - const String key (headerLines[i].upToFirstOccurrenceOf (":", false, false).trim()); - const String value (headerLines[i].fromFirstOccurrenceOf (":", false, false).trim()); - - if (key.isNotEmpty() && value.isNotEmpty()) - [req addValue: beastStringToNS (value) forHTTPHeaderField: beastStringToNS (key)]; - } - - if (isPost && postData.getSize() > 0) - [req setHTTPBody: [NSData dataWithBytes: postData.getData() - length: postData.getSize()]]; - - connection = new URLConnectionState (req); - - if (! connection->start (progressCallback, progressCallbackContext)) - connection = nullptr; - } - } -}; - -InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData, - OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, - const String& headers, const int timeOutMs, StringPairArray* responseHeaders) -{ - ScopedPointer wi (new WebInputStream (address, isPost, postData, - progressCallback, progressCallbackContext, - headers, timeOutMs, responseHeaders)); - - return wi->isError() ? nullptr : wi.release(); -} diff --git a/src/beast/modules/beast_core/native/mac_Threads.mm b/src/beast/modules/beast_core/native/mac_Threads.mm index fad59a4e22..f40d7b2593 100644 --- a/src/beast/modules/beast_core/native/mac_Threads.mm +++ b/src/beast/modules/beast_core/native/mac_Threads.mm @@ -59,7 +59,7 @@ void Process::setPriority (ProcessPriority) } //============================================================================== -BEAST_API bool BEAST_CALLTYPE beast_isRunningUnderDebugger() +bool beast_isRunningUnderDebugger() { static char testResult = 0; diff --git a/src/beast/modules/beast_core/native/win32_Network.cpp b/src/beast/modules/beast_core/native/win32_Network.cpp index f239d190c7..d85cc01de2 100644 --- a/src/beast/modules/beast_core/native/win32_Network.cpp +++ b/src/beast/modules/beast_core/native/win32_Network.cpp @@ -21,298 +21,6 @@ */ //============================================================================== -#ifndef INTERNET_FLAG_NEED_FILE - #define INTERNET_FLAG_NEED_FILE 0x00000010 -#endif - -#ifndef INTERNET_OPTION_DISABLE_AUTODIAL - #define INTERNET_OPTION_DISABLE_AUTODIAL 70 -#endif - -//============================================================================== -class WebInputStream - : public InputStream - , LeakChecked -{ -public: - WebInputStream (const String& address_, bool isPost_, const MemoryBlock& postData_, - URL::OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, - const String& headers_, int timeOutMs_, StringPairArray* responseHeaders) - : connection (0), request (0), - address (address_), headers (headers_), postData (postData_), position (0), - finished (false), isPost (isPost_), timeOutMs (timeOutMs_) - { - createConnection (progressCallback, progressCallbackContext); - - if (responseHeaders != nullptr && ! isError()) - { - DWORD bufferSizeBytes = 4096; - - for (;;) - { - HeapBlock buffer ((size_t) bufferSizeBytes); - - if (HttpQueryInfo (request, HTTP_QUERY_RAW_HEADERS_CRLF, buffer.getData(), &bufferSizeBytes, 0)) - { - StringArray headersArray; - headersArray.addLines (reinterpret_cast (buffer.getData())); - - for (int i = 0; i < headersArray.size(); ++i) - { - const String& header = headersArray[i]; - const String key (header.upToFirstOccurrenceOf (": ", false, false)); - const String value (header.fromFirstOccurrenceOf (": ", false, false)); - const String previousValue ((*responseHeaders) [key]); - - responseHeaders->set (key, previousValue.isEmpty() ? value : (previousValue + "," + value)); - } - - break; - } - - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) - break; - } - } - } - - ~WebInputStream() - { - close(); - } - - //============================================================================== - bool isError() const { return request == 0; } - bool isExhausted() { return finished; } - int64 getPosition() { return position; } - - int64 getTotalLength() - { - if (! isError()) - { - DWORD index = 0, result = 0, size = sizeof (result); - - if (HttpQueryInfo (request, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &result, &size, &index)) - return (int64) result; - } - - return -1; - } - - int read (void* buffer, int bytesToRead) - { - bassert (buffer != nullptr && bytesToRead >= 0); - DWORD bytesRead = 0; - - if (! (finished || isError())) - { - InternetReadFile (request, buffer, (DWORD) bytesToRead, &bytesRead); - position += bytesRead; - - if (bytesRead == 0) - finished = true; - } - - return (int) bytesRead; - } - - bool setPosition (int64 wantedPos) - { - if (isError()) - return false; - - if (wantedPos != position) - { - finished = false; - position = (int64) InternetSetFilePointer (request, (LONG) wantedPos, 0, FILE_BEGIN, 0); - - if (position == wantedPos) - return true; - - if (wantedPos < position) - { - close(); - position = 0; - createConnection (0, 0); - } - - skipNextBytes (wantedPos - position); - } - - return true; - } - -private: - //============================================================================== - HINTERNET connection, request; - String address, headers; - MemoryBlock postData; - int64 position; - bool finished; - const bool isPost; - int timeOutMs; - - void close() - { - if (request != 0) - { - InternetCloseHandle (request); - request = 0; - } - - if (connection != 0) - { - InternetCloseHandle (connection); - connection = 0; - } - } - - void createConnection (URL::OpenStreamProgressCallback* progressCallback, - void* progressCallbackContext) - { - static HINTERNET sessionHandle = InternetOpen (_T("beast"), INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, 0); - - close(); - - if (sessionHandle != 0) - { - // break up the url.. - const int fileNumChars = 65536; - const int serverNumChars = 2048; - const int usernameNumChars = 1024; - const int passwordNumChars = 1024; - HeapBlock file (fileNumChars), server (serverNumChars), - username (usernameNumChars), password (passwordNumChars); - - URL_COMPONENTS uc = { 0 }; - uc.dwStructSize = sizeof (uc); - uc.lpszUrlPath = file; - uc.dwUrlPathLength = fileNumChars; - uc.lpszHostName = server; - uc.dwHostNameLength = serverNumChars; - uc.lpszUserName = username; - uc.dwUserNameLength = usernameNumChars; - uc.lpszPassword = password; - uc.dwPasswordLength = passwordNumChars; - - if (InternetCrackUrl (address.toWideCharPointer(), 0, 0, &uc)) - openConnection (uc, sessionHandle, progressCallback, progressCallbackContext); - } - } - - void openConnection (URL_COMPONENTS& uc, HINTERNET sessionHandle, - URL::OpenStreamProgressCallback* progressCallback, - void* progressCallbackContext) - { - int disable = 1; - InternetSetOption (sessionHandle, INTERNET_OPTION_DISABLE_AUTODIAL, &disable, sizeof (disable)); - - if (timeOutMs == 0) - timeOutMs = 30000; - else if (timeOutMs < 0) - timeOutMs = -1; - - applyTimeout (sessionHandle, INTERNET_OPTION_CONNECT_TIMEOUT); - applyTimeout (sessionHandle, INTERNET_OPTION_RECEIVE_TIMEOUT); - applyTimeout (sessionHandle, INTERNET_OPTION_SEND_TIMEOUT); - applyTimeout (sessionHandle, INTERNET_OPTION_DATA_RECEIVE_TIMEOUT); - applyTimeout (sessionHandle, INTERNET_OPTION_DATA_SEND_TIMEOUT); - - const bool isFtp = address.startsWithIgnoreCase ("ftp:"); - - connection = InternetConnect (sessionHandle, uc.lpszHostName, uc.nPort, - uc.lpszUserName, uc.lpszPassword, - isFtp ? (DWORD) INTERNET_SERVICE_FTP - : (DWORD) INTERNET_SERVICE_HTTP, - 0, 0); - if (connection != 0) - { - if (isFtp) - request = FtpOpenFile (connection, uc.lpszUrlPath, GENERIC_READ, - FTP_TRANSFER_TYPE_BINARY | INTERNET_FLAG_NEED_FILE, 0); - else - openHTTPConnection (uc, progressCallback, progressCallbackContext); - } - } - - void applyTimeout (HINTERNET sessionHandle, const DWORD option) - { - InternetSetOption (sessionHandle, option, &timeOutMs, sizeof (timeOutMs)); - } - - void openHTTPConnection (URL_COMPONENTS& uc, URL::OpenStreamProgressCallback* progressCallback, - void* progressCallbackContext) - { - const TCHAR* mimeTypes[] = { _T("*/*"), nullptr }; - - DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES; - - if (address.startsWithIgnoreCase ("https:")) - flags |= INTERNET_FLAG_SECURE; // (this flag only seems necessary if the OS is running IE6 - - // IE7 seems to automatically work out when it's https) - - request = HttpOpenRequest (connection, isPost ? _T("POST") : _T("GET"), - uc.lpszUrlPath, 0, 0, mimeTypes, flags, 0); - - if (request != 0) - { - INTERNET_BUFFERS buffers = { 0 }; - buffers.dwStructSize = sizeof (INTERNET_BUFFERS); - buffers.lpcszHeader = headers.toWideCharPointer(); - buffers.dwHeadersLength = (DWORD) headers.length(); - buffers.dwBufferTotal = (DWORD) postData.getSize(); - - if (HttpSendRequestEx (request, &buffers, 0, HSR_INITIATE, 0)) - { - int bytesSent = 0; - - for (;;) - { - const int bytesToDo = bmin (1024, (int) postData.getSize() - bytesSent); - DWORD bytesDone = 0; - - if (bytesToDo > 0 - && ! InternetWriteFile (request, - static_cast (postData.getData()) + bytesSent, - (DWORD) bytesToDo, &bytesDone)) - { - break; - } - - if (bytesToDo == 0 || (int) bytesDone < bytesToDo) - { - if (HttpEndRequest (request, 0, 0, 0)) - return; - - break; - } - - bytesSent += bytesDone; - - if (progressCallback != nullptr - && ! progressCallback (progressCallbackContext, bytesSent, (int) postData.getSize())) - break; - } - } - } - - close(); - } -}; - -InputStream* URL::createNativeStream (const String& address, bool isPost, const MemoryBlock& postData, - OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, - const String& headers, const int timeOutMs, StringPairArray* responseHeaders) -{ - ScopedPointer wi (new WebInputStream (address, isPost, postData, - progressCallback, progressCallbackContext, - headers, timeOutMs, responseHeaders)); - - return wi->isError() ? nullptr : wi.release(); -} - - -//============================================================================== struct GetAdaptersInfoHelper { bool callGetAdaptersInfo() diff --git a/src/beast/modules/beast_core/native/win32_Threads.cpp b/src/beast/modules/beast_core/native/win32_Threads.cpp index a8d0e18fca..3cbc3afee3 100644 --- a/src/beast/modules/beast_core/native/win32_Threads.cpp +++ b/src/beast/modules/beast_core/native/win32_Threads.cpp @@ -257,7 +257,7 @@ void Process::setPriority (ProcessPriority prior) } } -BEAST_API bool BEAST_CALLTYPE beast_isRunningUnderDebugger() +bool beast_isRunningUnderDebugger() { return IsDebuggerPresent() != FALSE; } diff --git a/src/beast/modules/beast_core/streams/OutputStream.cpp b/src/beast/modules/beast_core/streams/OutputStream.cpp index e11249b8e5..26b91d8e02 100644 --- a/src/beast/modules/beast_core/streams/OutputStream.cpp +++ b/src/beast/modules/beast_core/streams/OutputStream.cpp @@ -414,3 +414,20 @@ BEAST_API bool OutputStream::writeTypeBigEndian (float v) { return write template <> BEAST_API bool OutputStream::writeTypeBigEndian (double v) { return writeDoubleBigEndian (v); } + +BEAST_API OutputStream& BEAST_CALLTYPE operator<< (OutputStream& stream, const String& text) +{ + const size_t numBytes = text.getNumBytesAsUTF8(); + + #if (BEAST_STRING_UTF_TYPE == 8) + stream.write (text.getCharPointer().getAddress(), numBytes); + #else + // (This avoids using toUTF8() to prevent the memory bloat that it would leave behind + // if lots of large, persistent strings were to be written to streams). + HeapBlock temp (numBytes + 1); + CharPointer_UTF8 (temp).writeAll (text.getCharPointer()); + stream.write (temp, numBytes); + #endif + + return stream; +} diff --git a/src/beast/modules/beast_core/streams/OutputStream.h b/src/beast/modules/beast_core/streams/OutputStream.h index f896568906..89ca7ca478 100644 --- a/src/beast/modules/beast_core/streams/OutputStream.h +++ b/src/beast/modules/beast_core/streams/OutputStream.h @@ -293,4 +293,7 @@ BEAST_API OutputStream& BEAST_CALLTYPE operator<< (OutputStream& stream, InputSt */ BEAST_API OutputStream& BEAST_CALLTYPE operator<< (OutputStream& stream, const NewLine&); +/** Writes a string to an OutputStream as UTF8. */ +BEAST_API OutputStream& BEAST_CALLTYPE operator<< (OutputStream& stream, const String& stringToWrite); + #endif diff --git a/src/beast/modules/beast_core/system/BeforeBoost.h b/src/beast/modules/beast_core/system/BeforeBoost.h index 601fa5a91f..ce9c2bc5e3 100644 --- a/src/beast/modules/beast_core/system/BeforeBoost.h +++ b/src/beast/modules/beast_core/system/BeforeBoost.h @@ -22,7 +22,6 @@ // TargetPlatform.h should not use anything from BeastConfig.h #include "../../../beast/Config.h" -#include "BeastConfigCheck.h" // This file should be included before including any boost headers. // If you don't include this file, and you include boost headers, diff --git a/src/beast/modules/beast_core/system/StandardIncludes.h b/src/beast/modules/beast_core/system/StandardIncludes.h new file mode 100644 index 0000000000..39994fa1a7 --- /dev/null +++ b/src/beast/modules/beast_core/system/StandardIncludes.h @@ -0,0 +1,78 @@ +//------------------------------------------------------------------------------ +/* + This file is part of Beast: https://github.com/vinniefalco/Beast + Copyright 2013, Vinnie Falco + + Portions of this file are from JUCE. + Copyright (c) 2013 - Raw Material Software Ltd. + Please visit http://www.juce.com + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef BEAST_STANDARDINCLUDES_H_INCLUDED +#define BEAST_STANDARDINCLUDES_H_INCLUDED + +// Include some common OS headers.. +#if BEAST_MSVC +#pragma warning (push) +#pragma warning (disable: 4514 4245 4100) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// undef symbols that are sometimes set by misguided 3rd-party headers.. +#undef check +#undef TYPE_BOOL +#undef max +#undef min + +#endif diff --git a/src/beast/modules/beast_sqlite/beast_sqlite.h b/src/beast/modules/beast_sqlite/beast_sqlite.h index 1c1b5c6152..ed63472e82 100644 --- a/src/beast/modules/beast_sqlite/beast_sqlite.h +++ b/src/beast/modules/beast_sqlite/beast_sqlite.h @@ -30,7 +30,7 @@ see BeastConfig.h. */ -#include "../../../beast/beast/Config.h" +#include "../../../beast/beast/config/PlatformConfig.h" #if BEAST_IOS || BEAST_MAC # define BEAST_HAVE_NATIVE_SQLITE 1 diff --git a/src/ripple/beast/ripple_beast.cpp b/src/ripple/beast/ripple_beast.cpp index 6e8bdf73cc..8b415e02ca 100644 --- a/src/ripple/beast/ripple_beast.cpp +++ b/src/ripple/beast/ripple_beast.cpp @@ -25,5 +25,7 @@ #include "../beast/modules/beast_db/beast_db.cpp" #include "../beast/modules/beast_sqdb/beast_sqdb.cpp" +#include "../beast/beast/http/HTTP.cpp" #include "../beast/beast/net/Net.cpp" +#include "../beast/beast/strings/Strings.cpp" #include "../beast/beast/utility/Utility.cpp" diff --git a/src/ripple/validators/api/Manager.h b/src/ripple/validators/api/Manager.h index 9df6d74e82..0a256b5484 100644 --- a/src/ripple/validators/api/Manager.h +++ b/src/ripple/validators/api/Manager.h @@ -7,8 +7,8 @@ #ifndef RIPPLE_VALIDATORS_MANAGER_H_INCLUDED #define RIPPLE_VALIDATORS_MANAGER_H_INCLUDED -namespace Validators -{ +namespace ripple { +namespace Validators { /** Maintains the list of chosen validators. @@ -57,7 +57,7 @@ public: /** Add a live source of validators from a trusted URL. The URL will be contacted periodically to update the list. */ - virtual void addURL (UniformResourceLocator const& url) = 0; + virtual void addURL (URL const& url) = 0; /** Add a live source of validators. The caller loses ownership of the object. @@ -79,6 +79,7 @@ public: virtual void receiveValidation (ReceivedValidation const& rv) = 0; }; +} } #endif diff --git a/src/ripple/validators/api/Source.h b/src/ripple/validators/api/Source.h index 8718f73aa1..a906ac7977 100644 --- a/src/ripple/validators/api/Source.h +++ b/src/ripple/validators/api/Source.h @@ -7,8 +7,8 @@ #ifndef RIPPLE_VALIDATORS_SOURCE_H_INCLUDED #define RIPPLE_VALIDATORS_SOURCE_H_INCLUDED -namespace Validators -{ +namespace ripple { +namespace Validators { /** A source of validator descriptors. */ class Source @@ -57,6 +57,7 @@ public: virtual Result fetch (CancelCallback& callback, Journal journal) = 0; }; +} } #endif diff --git a/src/ripple/validators/api/Types.h b/src/ripple/validators/api/Types.h index 6a5fb1eee2..deb4674e4f 100644 --- a/src/ripple/validators/api/Types.h +++ b/src/ripple/validators/api/Types.h @@ -7,8 +7,8 @@ #ifndef RIPPLE_VALIDATORS_TYPES_H_INCLUDED #define RIPPLE_VALIDATORS_TYPES_H_INCLUDED -namespace Validators -{ +namespace ripple { +namespace Validators { typedef RipplePublicKey PublicKey; typedef RipplePublicKeyHash PublicKeyHash; @@ -25,6 +25,7 @@ struct CancelCallback virtual bool shouldCancel () = 0; }; +} } #endif diff --git a/src/ripple/validators/impl/CancelCallbacks.h b/src/ripple/validators/impl/CancelCallbacks.h index 9718f03dde..3b8dca2c20 100644 --- a/src/ripple/validators/impl/CancelCallbacks.h +++ b/src/ripple/validators/impl/CancelCallbacks.h @@ -7,8 +7,8 @@ #ifndef RIPPLE_VALIDATORS_CANCELCALLBACKS_H_INCLUDED #define RIPPLE_VALIDATORS_CANCELCALLBACKS_H_INCLUDED -namespace Validators -{ +namespace ripple { +namespace Validators { // Dummy CancelCallback that does nothing // @@ -49,6 +49,7 @@ private: bool m_interrupted; }; +} } #endif diff --git a/src/ripple/validators/impl/ChosenList.h b/src/ripple/validators/impl/ChosenList.h index ef9252b8eb..09172b7c98 100644 --- a/src/ripple/validators/impl/ChosenList.h +++ b/src/ripple/validators/impl/ChosenList.h @@ -7,8 +7,8 @@ #ifndef RIPPLE_VALIDATORS_CHOSENLIST_H_INCLUDED #define RIPPLE_VALIDATORS_CHOSENLIST_H_INCLUDED -namespace Validators -{ +namespace ripple { +namespace Validators { class ChosenList : public SharedObject { @@ -59,6 +59,7 @@ private: MapType m_map; }; +} } #endif diff --git a/src/ripple/validators/impl/Logic.h b/src/ripple/validators/impl/Logic.h index ce244dd9af..3e4f955155 100644 --- a/src/ripple/validators/impl/Logic.h +++ b/src/ripple/validators/impl/Logic.h @@ -7,8 +7,8 @@ #ifndef RIPPLE_VALIDATORS_LOGIC_H_INCLUDED #define RIPPLE_VALIDATORS_LOGIC_H_INCLUDED -namespace Validators -{ +namespace ripple { +namespace Validators { // Tunable constants enum @@ -400,6 +400,7 @@ public: //---------------------------------------------------------------------- }; +} } #endif diff --git a/src/ripple/validators/impl/Manager.cpp b/src/ripple/validators/impl/Manager.cpp index 50472f4493..d74f63eea5 100644 --- a/src/ripple/validators/impl/Manager.cpp +++ b/src/ripple/validators/impl/Manager.cpp @@ -84,8 +84,8 @@ What determines that a validator is good? the behavior is measured. */ -namespace Validators -{ +namespace ripple { +namespace Validators { class ManagerImp : public Manager @@ -180,7 +180,7 @@ public: addStaticSource (SourceFile::New (file)); } - void addURL (UniformResourceLocator const& url) + void addURL (URL const& url) { addSource (SourceURL::New (url)); } @@ -308,3 +308,4 @@ Validators::Manager* Validators::Manager::New (Stoppable& parent, Journal journa } } +} diff --git a/src/ripple/validators/impl/Source.cpp b/src/ripple/validators/impl/Source.cpp index 3095574a93..c21f9b76b9 100644 --- a/src/ripple/validators/impl/Source.cpp +++ b/src/ripple/validators/impl/Source.cpp @@ -4,8 +4,8 @@ */ //============================================================================== -namespace Validators -{ +namespace ripple { +namespace Validators { Source::Result::Result () : success (false) @@ -21,3 +21,4 @@ void Source::Result::swapWith (Result& other) } } +} diff --git a/src/ripple/validators/impl/SourceDesc.h b/src/ripple/validators/impl/SourceDesc.h index 393a36091d..bfac5aefc2 100644 --- a/src/ripple/validators/impl/SourceDesc.h +++ b/src/ripple/validators/impl/SourceDesc.h @@ -7,8 +7,8 @@ #ifndef RIPPLE_VALIDATORS_SOURCEDESC_H_INCLUDED #define RIPPLE_VALIDATORS_SOURCEDESC_H_INCLUDED -namespace Validators -{ +namespace ripple { +namespace Validators { /** Additional state information associated with a Source. */ struct SourceDesc @@ -52,6 +52,7 @@ struct SourceDesc typedef DynamicList SourcesType; +} } #endif diff --git a/src/ripple/validators/impl/SourceFile.cpp b/src/ripple/validators/impl/SourceFile.cpp index 38fd5d9b97..d06c62eff6 100644 --- a/src/ripple/validators/impl/SourceFile.cpp +++ b/src/ripple/validators/impl/SourceFile.cpp @@ -4,8 +4,8 @@ */ //============================================================================== -namespace Validators -{ +namespace ripple { +namespace Validators { class SourceFileImp : public SourceFile { @@ -56,3 +56,4 @@ SourceFile* SourceFile::New (File const& file) } } +} diff --git a/src/ripple/validators/impl/SourceFile.h b/src/ripple/validators/impl/SourceFile.h index 0b6418d967..e3114990e3 100644 --- a/src/ripple/validators/impl/SourceFile.h +++ b/src/ripple/validators/impl/SourceFile.h @@ -7,8 +7,8 @@ #ifndef RIPPLE_VALIDATORS_SOURCEFILE_H_INCLUDED #define RIPPLE_VALIDATORS_SOURCEFILE_H_INCLUDED -namespace Validators -{ +namespace ripple { +namespace Validators { /** Provides validators from a text file. Typically this will come from a local configuration file. @@ -19,6 +19,7 @@ public: static SourceFile* New (File const& path); }; +} } #endif diff --git a/src/ripple/validators/impl/SourceStrings.cpp b/src/ripple/validators/impl/SourceStrings.cpp index c88a7da80e..32aa474c8c 100644 --- a/src/ripple/validators/impl/SourceStrings.cpp +++ b/src/ripple/validators/impl/SourceStrings.cpp @@ -4,8 +4,8 @@ */ //============================================================================== -namespace Validators -{ +namespace ripple { +namespace Validators { class SourceStringsImp : public SourceStrings { @@ -70,3 +70,4 @@ SourceStrings* SourceStrings::New ( } } +} diff --git a/src/ripple/validators/impl/SourceStrings.h b/src/ripple/validators/impl/SourceStrings.h index 3e1092a54d..35c4008a98 100644 --- a/src/ripple/validators/impl/SourceStrings.h +++ b/src/ripple/validators/impl/SourceStrings.h @@ -7,8 +7,8 @@ #ifndef RIPPLE_VALIDATORS_SOURCESTRINGS_H_INCLUDED #define RIPPLE_VALIDATORS_SOURCESTRINGS_H_INCLUDED -namespace Validators -{ +namespace ripple { +namespace Validators { /** Provides validators from a set of Validator strings. Typically this will come from a local configuration file. @@ -20,6 +20,7 @@ public: String name, StringArray const& strings); }; +} } #endif diff --git a/src/ripple/validators/impl/SourceURL.cpp b/src/ripple/validators/impl/SourceURL.cpp index 07fd548d75..c08d82cb07 100644 --- a/src/ripple/validators/impl/SourceURL.cpp +++ b/src/ripple/validators/impl/SourceURL.cpp @@ -4,13 +4,13 @@ */ //============================================================================== -namespace Validators -{ +namespace ripple { +namespace Validators { class SourceURLImp : public SourceURL { public: - explicit SourceURLImp (UniformResourceLocator const& url) + explicit SourceURLImp (URL const& url) : m_url (url) { } @@ -57,13 +57,13 @@ public: } private: - UniformResourceLocator m_url; + URL m_url; }; //------------------------------------------------------------------------------ SourceURL* SourceURL::New ( - UniformResourceLocator const& url) + URL const& url) { ScopedPointer object ( new SourceURLImp (url)); @@ -72,3 +72,4 @@ SourceURL* SourceURL::New ( } } +} diff --git a/src/ripple/validators/impl/SourceURL.h b/src/ripple/validators/impl/SourceURL.h index 9015e003fe..50a2eb41ba 100644 --- a/src/ripple/validators/impl/SourceURL.h +++ b/src/ripple/validators/impl/SourceURL.h @@ -7,17 +7,17 @@ #ifndef RIPPLE_VALIDATORS_SOURCEURL_H_INCLUDED #define RIPPLE_VALIDATORS_SOURCEURL_H_INCLUDED -namespace Validators -{ +namespace ripple { +namespace Validators { -/** Provides validators from a trusted URI (e.g. HTTPS) -*/ +/** Provides validators from a trusted URI (e.g. HTTPS) */ class SourceURL : public Source { public: - static SourceURL* New (UniformResourceLocator const& url); + static SourceURL* New (URL const& url); }; +} } #endif diff --git a/src/ripple/validators/impl/Store.h b/src/ripple/validators/impl/Store.h index e3ffcd411b..f806238b18 100644 --- a/src/ripple/validators/impl/Store.h +++ b/src/ripple/validators/impl/Store.h @@ -7,8 +7,8 @@ #ifndef RIPPLE_VALIDATORS_STORE_H_INCLUDED #define RIPPLE_VALIDATORS_STORE_H_INCLUDED -namespace Validators -{ +namespace ripple { +namespace Validators { /** Abstract persistence for Validators data. */ class Store @@ -29,6 +29,7 @@ protected: Store () { } }; +} } #endif diff --git a/src/ripple/validators/impl/StoreSqdb.cpp b/src/ripple/validators/impl/StoreSqdb.cpp index 3615a1b023..b236f1d5c6 100644 --- a/src/ripple/validators/impl/StoreSqdb.cpp +++ b/src/ripple/validators/impl/StoreSqdb.cpp @@ -4,8 +4,8 @@ */ //============================================================================== -namespace Validators -{ +namespace ripple { +namespace Validators { StoreSqdb::StoreSqdb (Journal journal) : m_journal (journal) @@ -343,3 +343,4 @@ Error StoreSqdb::init () } } +} diff --git a/src/ripple/validators/impl/StoreSqdb.h b/src/ripple/validators/impl/StoreSqdb.h index 2f0924bb89..b302393260 100644 --- a/src/ripple/validators/impl/StoreSqdb.h +++ b/src/ripple/validators/impl/StoreSqdb.h @@ -7,8 +7,8 @@ #ifndef RIPPLE_VALIDATORS_STORESQDB_H_INCLUDED #define RIPPLE_VALIDATORS_STORESQDB_H_INCLUDED -namespace Validators -{ +namespace ripple { +namespace Validators { /** Database persistence for Validators using SQLite */ class StoreSqdb : public Store @@ -36,6 +36,7 @@ private: sqdb::session m_session; }; +} } #endif diff --git a/src/ripple/validators/impl/Tests.cpp b/src/ripple/validators/impl/Tests.cpp index 563435a3a1..0a2aeb62f5 100644 --- a/src/ripple/validators/impl/Tests.cpp +++ b/src/ripple/validators/impl/Tests.cpp @@ -4,8 +4,8 @@ */ //============================================================================== -namespace Validators -{ +namespace ripple { +namespace Validators { class Tests : public UnitTest { @@ -220,3 +220,4 @@ public: static Tests tests; } +} diff --git a/src/ripple/validators/impl/Utilities.cpp b/src/ripple/validators/impl/Utilities.cpp index bdfabf944f..c916afa790 100644 --- a/src/ripple/validators/impl/Utilities.cpp +++ b/src/ripple/validators/impl/Utilities.cpp @@ -4,8 +4,8 @@ */ //============================================================================== -namespace Validators -{ +namespace ripple { +namespace Validators { struct Utilities::Helpers { @@ -252,3 +252,4 @@ PublicKey Utilities::stringToPublicKey (std::string const& s) //------------------------------------------------------------------------------ } +} diff --git a/src/ripple/validators/impl/Utilities.h b/src/ripple/validators/impl/Utilities.h index f99b2c7dea..ab8ccd00f8 100644 --- a/src/ripple/validators/impl/Utilities.h +++ b/src/ripple/validators/impl/Utilities.h @@ -7,8 +7,8 @@ #ifndef RIPPLE_VALIDATORS_UTILITIES_H_INCLUDED #define RIPPLE_VALIDATORS_UTILITIES_H_INCLUDED -namespace Validators -{ +namespace ripple { +namespace Validators { /** Common code for Validators classes. */ @@ -67,6 +67,7 @@ public: Source::Info& info, std::string const& line, Journal journal); }; +} } #endif diff --git a/src/ripple/validators/ripple_validators.cpp b/src/ripple/validators/ripple_validators.cpp index 706c905917..b42f9b3586 100644 --- a/src/ripple/validators/ripple_validators.cpp +++ b/src/ripple/validators/ripple_validators.cpp @@ -12,12 +12,16 @@ #include #include +#include "beast/modules/beast_asio/beast_asio.h" #include "beast/modules/beast_sqdb/beast_sqdb.h" +#include "../ripple_data/ripple_data.h" // for RippleAddress REMOVE ASAP + #include "../testoverlay/ripple_testoverlay.h" // for unit test -namespace ripple -{ +namespace ripple { +using namespace beast; +} # include "impl/CancelCallbacks.h" # include "impl/ChosenList.h" @@ -38,5 +42,3 @@ namespace ripple #include "impl/StoreSqdb.cpp" #include "impl/Tests.cpp" #include "impl/Utilities.cpp" - -} diff --git a/src/ripple/validators/ripple_validators.h b/src/ripple/validators/ripple_validators.h index 70d0bccc38..25e4e841d7 100644 --- a/src/ripple/validators/ripple_validators.h +++ b/src/ripple/validators/ripple_validators.h @@ -7,28 +7,16 @@ #ifndef RIPPLE_VALIDATORS_H_INCLUDED #define RIPPLE_VALIDATORS_H_INCLUDED -// VFALCO TODO Remove buffers/beast_asio dependency -// -// VFALCO NOTE It is unfortunate that we are exposing boost/asio.hpp -// needlessly. Its only required because of the buffers types. -// The HTTPClient interface doesn't need asio (although the -// implementation does. This is also required for -// UniformResourceLocator. -// -#include "beast/modules/beast_asio/beast_asio.h" +#include "beast/modules/beast_core/beast_core.h" +#include "../ripple_basics/ripple_basics.h" // for RipplePublicKey, remove asap + +#include "beast/beast/http/URL.h" #include "../ripple/rpc/ripple_rpc.h" -#include "../ripple_data/ripple_data.h" - -namespace ripple -{ - -using namespace beast; +#include "../ripple/types/ripple_types.h" # include "api/Types.h" # include "api/Source.h" #include "api/Manager.h" -} - #endif diff --git a/src/ripple_app/main/Application.h b/src/ripple_app/main/Application.h index 2ae5c1bcad..17fbaaeaf2 100644 --- a/src/ripple_app/main/Application.h +++ b/src/ripple_app/main/Application.h @@ -9,6 +9,7 @@ namespace Validators { class Manager; } namespace NodeStore { class Database; } +namespace RPC { class Manager; } // VFALCO TODO Fix forward declares required for header dependency loops class IFeatures; diff --git a/src/ripple_app/ripple_app.h b/src/ripple_app/ripple_app.h index a5133272f4..07776ccdab 100644 --- a/src/ripple_app/ripple_app.h +++ b/src/ripple_app/ripple_app.h @@ -39,7 +39,7 @@ #include "../ripple_data/ripple_data.h" #include "../ripple_net/ripple_net.h" -#include "beast/modules/beast_sqdb/beast_sqdb.h" +//#include "beast/modules/beast_sqdb/beast_sqdb.h" #include "beast/modules/beast_sqlite/beast_sqlite.h" // VFALCO NOTE If we forward declare PackedMessage and write out shared_ptr diff --git a/src/ripple_core/functional/Config.cpp b/src/ripple_core/functional/Config.cpp index 4c7413cffc..8012b1f0e0 100644 --- a/src/ripple_core/functional/Config.cpp +++ b/src/ripple_core/functional/Config.cpp @@ -20,7 +20,6 @@ Config::Config () : m_rpcPort (5001) - , SSL_CONTEXT (boost::asio::ssl::context::sslv23) { //-------------------------------------------------------------------------- // @@ -190,24 +189,7 @@ void Config::setup (const std::string& strConf, bool bTestNet, bool bQuiet) } } - - if (SSL_VERIFY_FILE.empty ()) - { - SSL_CONTEXT.set_default_verify_paths (ec); - - if (ec && SSL_VERIFY_DIR.empty ()) - throw std::runtime_error (boost::str (boost::format ("Failed to set_default_verify_paths: %s") % ec.message ())); - } - else - SSL_CONTEXT.load_verify_file (SSL_VERIFY_FILE); - - if (!SSL_VERIFY_DIR.empty ()) - { - SSL_CONTEXT.add_verify_path (SSL_VERIFY_DIR, ec); - - if (ec) - throw std::runtime_error (boost::str (boost::format ("Failed to add verify path: %s") % ec.message ())); - } + HTTPClient::initializeSSLContext(); // Update default values load (); @@ -736,7 +718,7 @@ File Config::getValidatorsFile () const return File::nonexistent (); } -UniformResourceLocator Config::getValidatorsURL () const +URL Config::getValidatorsURL () const { //String s = "https://" + VALIDATORS_SITE + VALIDATORS_URI; String s = VALIDATORS_SITE; diff --git a/src/ripple_core/functional/Config.h b/src/ripple_core/functional/Config.h index f7798c43e9..d1a33f5a3c 100644 --- a/src/ripple_core/functional/Config.h +++ b/src/ripple_core/functional/Config.h @@ -199,7 +199,7 @@ public: File getValidatorsFile () const; /** Returns the optional URL to a trusted network source of validators. */ - UniformResourceLocator getValidatorsURL () const; + URL getValidatorsURL () const; // DEPRECATED boost::filesystem::path VALIDATORS_FILE; // As specifed in rippled.cfg. @@ -443,7 +443,6 @@ public: uint32 SIGN_VALIDATION; uint32 SIGN_PROPOSAL; - boost::asio::ssl::context SSL_CONTEXT; // Generic SSL context. bool SSL_VERIFY; std::string SSL_VERIFY_FILE; std::string SSL_VERIFY_DIR; diff --git a/src/ripple_core/peerfinder/PeerFinder.h b/src/ripple_core/peerfinder/PeerFinder.h index 7b9199c6ba..1c19f12f19 100644 --- a/src/ripple_core/peerfinder/PeerFinder.h +++ b/src/ripple_core/peerfinder/PeerFinder.h @@ -34,15 +34,14 @@ public: //-------------------------------------------------------------------------- - /** An abstract address that can be turned into a socket endpoint. - */ + /** An abstract address that can be turned into a socket endpoint. */ struct Address { virtual String asString () = 0; }; - /** An IPv4 address. - */ + /** An IPv4 address. */ +#if 0 struct AddressIPv4 : Address { AddressIPv4 (InputParser::IPv4Address const& address, uint16 port) @@ -66,6 +65,7 @@ public: InputParser::IPv4Address m_address; uint16 m_port; }; +#endif //-------------------------------------------------------------------------- diff --git a/src/ripple_core/ripple_core.cpp b/src/ripple_core/ripple_core.cpp index 6f237cb37f..ab11fbbd6d 100644 --- a/src/ripple_core/ripple_core.cpp +++ b/src/ripple_core/ripple_core.cpp @@ -20,6 +20,8 @@ #include "nodestore/NodeStore.cpp" +#include "../ripple_net/ripple_net.h" // for HTTPClient + namespace ripple { diff --git a/src/ripple_core/ripple_core.h b/src/ripple_core/ripple_core.h index aecd72d920..ba1fba0012 100644 --- a/src/ripple_core/ripple_core.h +++ b/src/ripple_core/ripple_core.h @@ -7,13 +7,10 @@ #ifndef RIPPLE_CORE_H_INCLUDED #define RIPPLE_CORE_H_INCLUDED -// VFALCO TODO For UniformResourceLocator, remove asap -#include "beast/modules/beast_asio/beast_asio.h" - -#include "../ripple/rpc/ripple_rpc.h" #include "../ripple_basics/ripple_basics.h" #include "../ripple_data/ripple_data.h" +#include "beast/beast/http/URL.h" // for Config #include "nodestore/NodeStore.h" diff --git a/src/ripple_net/basics/HTTPClient.cpp b/src/ripple_net/basics/HTTPClient.cpp index 86e8671b0f..f5f0b0287a 100644 --- a/src/ripple_net/basics/HTTPClient.cpp +++ b/src/ripple_net/basics/HTTPClient.cpp @@ -10,19 +10,70 @@ SETUP_LOG (HTTPClient) +//------------------------------------------------------------------------------ + +class HTTPClientSSLContext +{ +public: + HTTPClientSSLContext () + : m_context (boost::asio::ssl::context::sslv23) + { + boost::system::error_code ec; + + if (getConfig().SSL_VERIFY_FILE.empty ()) + { + m_context.set_default_verify_paths (ec); + + if (ec && getConfig().SSL_VERIFY_DIR.empty ()) + throw std::runtime_error (boost::str ( + boost::format ("Failed to set_default_verify_paths: %s") % ec.message ())); + } + else + { + m_context.load_verify_file (getConfig().SSL_VERIFY_FILE); + } + + if (! getConfig().SSL_VERIFY_DIR.empty ()) + { + m_context.add_verify_path (getConfig().SSL_VERIFY_DIR, ec); + + if (ec) + throw std::runtime_error (boost::str ( + boost::format ("Failed to add verify path: %s") % ec.message ())); + } + } + + boost::asio::ssl::context& context() + { + return m_context; + } + +private: + boost::asio::ssl::context m_context; +}; + +//------------------------------------------------------------------------------ + +// VFALCO NOTE I moved the SSL_CONTEXT out of the Config and into this +// singleton to eliminate the asio dependency in the headers. +// +void HTTPClient::initializeSSLContext () +{ + SharedSingleton ::get(); +} + +//------------------------------------------------------------------------------ + class HTTPClientImp : public boost::enable_shared_from_this , public HTTPClient , LeakChecked { public: - // VFALCO NOTE Why use getConfig ().SSL_CONTEXT instead of just passing it? - // TODO Remove all theConfig deps from this file - // HTTPClientImp (boost::asio::io_service& io_service, const unsigned short port, std::size_t responseMax) - : mSocket (io_service, getConfig ().SSL_CONTEXT) + : mSocket (io_service, SharedSingleton ::get()->context()) , mResolver (io_service) , mHeader (maxClientHeaderBytes) , mPort (port) diff --git a/src/ripple_net/basics/HTTPClient.h b/src/ripple_net/basics/HTTPClient.h index 0ffabf6526..01c2344981 100644 --- a/src/ripple_net/basics/HTTPClient.h +++ b/src/ripple_net/basics/HTTPClient.h @@ -17,6 +17,8 @@ public: maxClientHeaderBytes = 32 * 1024 }; + static void initializeSSLContext (); + static void get ( bool bSSL, boost::asio::io_service& io_service,